Skip to content

feat: reconcile deployed 0.4.0 ghost into main — OTLP sink, MultiSink, rm-rf rule (+ preserve A4) - #9

Merged
buihongduc132 merged 3 commits into
mainfrom
feat/reconcile-040-ghost
Jul 24, 2026
Merged

feat: reconcile deployed 0.4.0 ghost into main — OTLP sink, MultiSink, rm-rf rule (+ preserve A4)#9
buihongduc132 merged 3 commits into
mainfrom
feat/reconcile-040-ghost

Conversation

@buihongduc132

@buihongduc132 buihongduc132 commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Reconcile deployed 0.4.0 ghost into repo main

Problem

The deployed production copy of pi-opa-net (~/.pi/agent/npm/node_modules/pi-opa-net/) contained unpublished features (OTLP/HTTP audit sink, MultiSink, config-driven audit factory, rm -rf dangerous-target policy) that had never been committed to git. Worse, the ghost release silently dropped the A4 runtime self-check layer (markHookRegistered() + runtime-self-check.ts) that was added in PR #7.

This meant:

  • Repo main (0.3.3) had A4 but lacked 0.4.0 features.
  • Deployed prod (0.4.0) had the features but lost A4.
  • npm registry still at 0.3.2 (no A4, no 0.4.0 features).

What this PR does

Reconciles the ghost into repo main on branch feat/reconcile-040-ghost:

  1. RED (commit 02723a3): added 16 failing tests for the 0.4.0 ghost features (MultiSink, OtlpAuditSink, sinkFactory, rm-rf rule).
  2. GREEN (commit c110100): implemented the features by copying/adapting the ghost source, preserving A4 untouched.
  3. Docs/version (commit `fa17a5b): added OTLP env vars + rm-rf rule docs, bumped to 0.4.1.

Changes

  • src/audit/MultiSink.ts — fan-out audit dispatch (filesystem + OTLP simultaneously), per-child error isolation.
  • src/audit/OtlpAuditSink.ts — OTLP/HTTP logs sink; graceful degradation (network failure is non-fatal).
  • src/audit/sinkFactory.ts — config-driven audit factory (PIOPANET_OTEL_ENABLED, PIOPANET_OTEL_ENDPOINT, etc.).
  • src/pi/tool-call.ts — wire default sink through createAuditSink({cwd}).
  • src/rules/catalog.ts + policy/safety.rego — add block-rm-rf-dangerous-target rule (blocks rm -rf on /, ~, ., .., *, /*, /home/bhd, /home; carve-outs preserved).
  • README.md + skills/pi-opa-net/SKILL.md — document OTLP env vars + new rule.
  • CHANGELOG.md — [0.4.1] entry.
  • package.json — bump to 0.4.1.

Verification

  • bun run check432 pass, 0 fail (typecheck + lint:ci + test --coverage).
  • Verifier loop feat(signals): conditional branch gate + context/signals for OPA policies #2 (pre-merge): all 10 checks PASS (see /tmp/verifier2-premerge.md).
  • A4 confirmed intact: markHookRegistered present in src/pi/index.ts lines 3 + 30; runtime-self-check.ts unchanged.
  • pi-session-smoke.test.ts (live pi E2E gate) passes standalone (3/3, twice).

After merge

  • npm publish to push 0.4.1 to registry.
  • pi install pi-opa-net@latest to redeploy prod with both 0.4.0 features AND A4.
  • Post-deploy verifier loop will confirm deployed behavior.

Summary by cubic

Reconciles the deployed 0.4.0 ghost into pi-opa-net main, adding OTLP/HTTP audit export, MultiSink fan-out, and a safety rule for dangerous rm -rf targets while keeping the A4 runtime self-check intact. Ships as 0.4.1 with docs and tests; default behavior stays the same.

  • New Features

    • Added OTLP/HTTP audit sink and MultiSink fan-out with per-child error isolation; network failures are non-fatal.
    • Introduced env-driven audit factory (PIOPANET_OTEL_ENABLED, PIOPANET_OTEL_ENDPOINT, PIOPANET_OTEL_SERVICE_NAME, PIOPANET_OTEL_HEADERS); default remains filesystem-only, and tool-call now uses it.
    • Added block-rm-rf-dangerous-target rule with safe carve-outs (/tmp/<specific>, ./<specific>); docs updated.
  • Migration

    • No breaking changes. Defaults unchanged.
    • To enable OTLP: set PIOPANET_OTEL_ENABLED=1 and PIOPANET_OTEL_ENDPOINT=<http://.../v1/logs> (optional: PIOPANET_OTEL_SERVICE_NAME, PIOPANET_OTEL_HEADERS).

Written for commit fa17a5b. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added optional OTLP/HTTP forwarding for audit events, configurable through environment variables.
    • Added the block-rm-rf-dangerous-target safety rule to block recursive forced deletion of dangerous paths while allowing safe paths.
    • Updated the release version to 0.4.1.
  • Bug Fixes

    • Restored the runtime self-check behavior from the 0.4.0 deployment.
  • Documentation

    • Documented audit forwarding configuration and the new safety rule.

buihongduc132 added 3 commits July 24, 2026 10:44
…ink, sinkFactory, rm-rf rule)

Strict TDD RED phase. 4 new test files, 16 failing tests, 0 implementation.

Test matrix:
- tests/unit/audit/MultiSink.test.ts (5 tests): fan-out, sequential ordering,
  per-child error isolation, stderr logging with [pi-opa-net] prefix.
- tests/unit/audit/OtlpAuditSink.test.ts (6 tests): OTLP Logs JSON body shape,
  severityText deny→ERROR/allow→INFO, resource.service.name, kvlistValue keys,
  fetch headers/method, fetch-reject graceful degradation.
- tests/unit/audit/sinkFactory.test.ts (9 tests): env-driven factory routing
  (OTel disabled → fs only; OTel+endpoint → MultiSink; OTel+no-endpoint → fs+warn),
  parseHeaders edge cases, env param override precedence.
- tests/e2e/block-rm-rf-dangerous-target.test.ts (13 tests): DENY on /, ~, ., ..,
  /*, $HOME, /home, -rf -rf /, -fr /; ALLOW on /tmp/specific-dir, ./subdir, rm -r /;
  catalog-registration precondition ensures ALL tests fail until rule is added.

RED confirmation: bun test → 399 pass (baseline preserved), 16 fail (all new).
GREEN phase: implement src/audit/{MultiSink,OtlpAuditSink,sinkFactory}.ts,
adapt src/pi/tool-call.ts, insert catalog entry + rego block for rm-rf rule.

Reference: /tmp/scout-ghost-drift.md (port plan)
…, rm-rf rule (+ preserve A4)

0.4.0 was deployed as a ghost binary without a matching repo commit. This brings the source tree in sync with that deployed artifact while preserving the A4 runtime self-check layer unchanged.

Changes copied/adapted from /tmp/piopanet-040-ghost/:

- src/audit/MultiSink.ts (verbatim)

- src/audit/OtlpAuditSink.ts (verbatim)

- src/audit/sinkFactory.ts (verbatim + exported parseHeaders for RED test)

- policy/safety.rego: block-rm-rf-dangerous-target rule block (verbatim)

- src/rules/catalog.ts: block-rm-rf-dangerous-target entry

- src/pi/tool-call.ts: use createAuditSink({ cwd }) from new sink factory

- tests/unit/audit/sinkFactory.test.ts: biome auto-format (no semantic change)

RED commit: 02723a3
- CHANGELOG [0.4.1] entry: reconcile deployed 0.4.0 ghost (OTLP, MultiSink, sinkFactory, rm-rf) + preserve A4
- README: add OTLP audit sink env vars + rm-rf dangerous-target rule
- SKILL.md: same env vars + rule
- package.json: 0.3.3 → 0.4.1
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Audit sink routing

Layer / File(s) Summary
Audit sink implementations
src/audit/MultiSink.ts, src/audit/OtlpAuditSink.ts
Adds sequential audit fan-out and OTLP/HTTP log export with structured fields and non-fatal failures.
Environment-based sink wiring
src/audit/sinkFactory.ts, src/pi/tool-call.ts
Selects filesystem-only or combined filesystem and OTLP sinks from environment configuration and uses the factory for blocked tool-call audits.
Audit sink validation
tests/unit/audit/*
Tests fan-out behavior, OTLP payloads and requests, error handling, header parsing, and environment precedence.

Dangerous rm policy

Layer / File(s) Summary
Dangerous-target rule definition
policy/safety.rego, src/rules/catalog.ts
Blocks recursive forced removal of dangerous literal or raw command targets and registers the rule in the catalog.
End-to-end rule validation
tests/e2e/block-rm-rf-dangerous-target.test.ts
Exercises denied commands, allowed carve-outs, registration checks, subprocess handling, timeouts, and unavailable-OPA skipping.

Release metadata and documentation

Layer / File(s) Summary
Release and configuration documentation
package.json, CHANGELOG.md, README.md, skills/pi-opa-net/SKILL.md
Bumps the version to 0.4.1 and documents the audit sink configuration and dangerous-target rule.

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

Sequence Diagram(s)

sequenceDiagram
  participant ToolCall
  participant SinkFactory
  participant MultiSink
  participant FileAudit
  participant OtlpAudit
  participant Collector
  ToolCall->>SinkFactory: createAuditSink(cwd)
  SinkFactory->>MultiSink: configure filesystem and OTLP sinks
  ToolCall->>MultiSink: write(audit entry)
  MultiSink->>FileAudit: write(audit entry)
  MultiSink->>OtlpAudit: write(audit entry)
  OtlpAudit->>Collector: POST OTLP Logs JSON
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change set: reconciling deployed features into main, including OTLP auditing, MultiSink, and the rm-rf safety rule.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reconcile-040-ghost

Comment @coderabbitai help to get the list of available commands.

@kilo-code-bot

kilo-code-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

Kilo Code Review could not run — your account is out of credits.

Add credits or switch to a free model to enable reviews on this change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
policy/safety.rego (1)

372-388: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated deny message literal across both branches.

The exact same message string is repeated in the args-based (line 378) and raw-based (line 387) deny rules. Extracting it to a shared variable would prevent future edits from silently diverging between the two branches.

♻️ Proposed dedup
+rm_dangerous_target_msg := "rm -rf on dangerous targets (/, ~, ., .., *, /*, $HOME, /home) is blocked. Use specific paths like /tmp/dir or ./subdir."
+
 # Args-based deny: dangerous literal target present in args
 deny[msg] if {
     input.program == "rm"
     rm_has_recursive(input.args)
     rm_has_force(input.args)
     rm_has_dangerous_arg_target(input.args)
-    msg := "rm -rf on dangerous targets (/, ~, ., .., *, /*, $HOME, /home) is blocked. Use specific paths like /tmp/dir or ./subdir."
+    msg := rm_dangerous_target_msg
 }

 # Raw-based deny: dangerous glob/env token present in raw (disappeared from args)
 deny[msg] if {
     input.program == "rm"
     rm_has_recursive(input.args)
     rm_has_force(input.args)
     rm_raw_dangerous_token(input.raw)
-    msg := "rm -rf on dangerous targets (/, ~, ., .., *, /*, $HOME, /home) is blocked. Use specific paths like /tmp/dir or ./subdir."
+    msg := rm_dangerous_target_msg
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy/safety.rego` around lines 372 - 388, Define a shared variable for the
rm safety denial message in policy/safety.rego, then have both deny rules using
rm_has_dangerous_arg_target and rm_raw_dangerous_token assign msg from that
variable instead of duplicating the literal. Preserve the existing message text
and rule behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 223: Update the dangerous-target catalogs to include the implemented ~/*
pattern, preserving the existing wording and formatting: add ~/* in README.md
lines 223-223, skills/pi-opa-net/SKILL.md lines 74-74, and CHANGELOG.md lines
13-13.

In `@src/audit/OtlpAuditSink.ts`:
- Line 104: Update the timeUnixNano assignment in the OTLP audit export to
compute nanoseconds with BigInt before stringification, using BigInt(Date.now())
and a BigInt nanosecond multiplier to avoid unsafe Number arithmetic.
- Around line 54-70: Update OtlpAuditSink.write to bound the fetch duration with
an AbortController-based timeout, and validate the response after fetch so
non-2xx statuses throw and enter the existing error logging path. Preserve the
non-fatal behavior by continuing to catch timeout, network, and HTTP-status
failures without propagating them.

In `@tests/e2e/block-rm-rf-dangerous-target.test.ts`:
- Around line 32-34: Update the OPA_BIN fallback used by the e2e test to use the
PATH-resolved command name “opa” instead of the machine-specific absolute path,
while preserving the OPA_AVAILABLE and SKIP_REASON behavior.

---

Nitpick comments:
In `@policy/safety.rego`:
- Around line 372-388: Define a shared variable for the rm safety denial message
in policy/safety.rego, then have both deny rules using
rm_has_dangerous_arg_target and rm_raw_dangerous_token assign msg from that
variable instead of duplicating the literal. Preserve the existing message text
and rule behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ed7bd169-4f69-488c-a3d1-d47f3806d9b5

📥 Commits

Reviewing files that changed from the base of the PR and between e00b775 and fa17a5b.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • README.md
  • package.json
  • policy/safety.rego
  • skills/pi-opa-net/SKILL.md
  • src/audit/MultiSink.ts
  • src/audit/OtlpAuditSink.ts
  • src/audit/sinkFactory.ts
  • src/pi/tool-call.ts
  • src/rules/catalog.ts
  • tests/e2e/block-rm-rf-dangerous-target.test.ts
  • tests/unit/audit/MultiSink.test.ts
  • tests/unit/audit/OtlpAuditSink.test.ts
  • tests/unit/audit/sinkFactory.test.ts

Comment thread README.md

### Rules

- `block-rm-rf-dangerous-target` — blocks `rm -rf` on `/`, `~`, `.`, `..`, `*`, `/*`, `$HOME`, `/home`. Safe carve-outs: `/tmp/<specific>`, `./<specific>`, named dirs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the implemented ~/* dangerous target consistently.

The Rego policy blocks ~/*, but all three user-facing/release descriptions omit it. Add ~/* to each listed dangerous-target catalog so the documentation matches policy/safety.rego.

  • README.md#L223-L223: add ~/* to the blocked target list.
  • skills/pi-opa-net/SKILL.md#L74-L74: add ~/* to the blocked target list.
  • CHANGELOG.md#L13-L13: add ~/* to the 0.4.1 release-note target list.
📍 Affects 3 files
  • README.md#L223-L223 (this comment)
  • skills/pi-opa-net/SKILL.md#L74-L74
  • CHANGELOG.md#L13-L13
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 223, Update the dangerous-target catalogs to include the
implemented ~/* pattern, preserving the existing wording and formatting: add ~/*
in README.md lines 223-223, skills/pi-opa-net/SKILL.md lines 74-74, and
CHANGELOG.md lines 13-13.

Comment on lines +54 to +70
async write(entry: unknown): Promise<void> {
const body = this.buildOtlpBody(entry as AuditEntry);
try {
await fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...this.headers },
body: JSON.stringify(body),
});
} catch (err) {
// Audit export failure is non-fatal — log to stderr and continue.
console.error(
`[pi-opa-net] OTLP audit export failed, continuing without OTel: ${
err instanceof Error ? err.message : String(err)
}`,
);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== File map ==\n'
git ls-files 'src/audit/OtlpAuditSink.ts' 'src/pi/tool-call.ts' 'src/audit/*' | sed 's#^`#-` #'

printf '\n== OtlpAuditSink outline ==\n'
ast-grep outline src/audit/OtlpAuditSink.ts --view expanded || true

printf '\n== Relevant slices ==\n'
sed -n '1,220p' src/audit/OtlpAuditSink.ts | cat -n
printf '\n--- tool-call slice ---\n'
sed -n '120,190p' src/pi/tool-call.ts | cat -n

Repository: buihongduc132/opa-net

Length of output: 1919


🌐 Web query:

Bun fetch default timeout AbortSignal.timeout documentation

💡 Result:

In Bun, fetch() supports AbortSignal.timeout() as a standard way to manage request timeouts, but it also features a native timeout option in its RequestInit configuration [1][2][3]. Key details regarding timeout behavior in Bun: 1. Native Timeout Support: Beyond AbortSignal, Bun allows you to pass a timeout property directly in the fetch options object (e.g., fetch(url, { timeout: 5000 })) [3]. 2. Default Timeout Behavior: Historically, Bun implemented a default idle socket timeout to prevent requests from hanging indefinitely [2][4]. Recent updates have refined this, distinguishing between a whole-request deadline (timeout) and specific phases like connection or inactivity (connectTimeout, socketTimeout) [2]. 3. Disabling Timeouts: You can disable the default request timeout by setting { timeout: false } or { timeout: 0 } in the fetch options [2][4]. This is often used as an "escape hatch" for long-polling or Server-Sent Events (SSE) [2]. 4. Interaction with AbortSignal: AbortSignal.timeout(ms) is the standard Web API way to trigger an AbortError after a specific duration [1][5]. While you can use both native timeout and AbortSignal.timeout simultaneously, they serve as different mechanisms for managing request lifecycle [2]. For authoritative guidance, refer to the official Bun networking documentation, which explicitly recommends AbortSignal.timeout for standard use cases [1]. Note that Bun's internal implementation of these timeouts continues to evolve to better support diverse networking requirements [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== OtlpAuditSink outline ==\n'
ast-grep outline src/audit/OtlpAuditSink.ts --view expanded || true

printf '\n== OtlpAuditSink lines 1-220 ==\n'
sed -n '1,220p' src/audit/OtlpAuditSink.ts | cat -n

printf '\n== tool-call lines 120-190 ==\n'
sed -n '120,190p' src/pi/tool-call.ts | cat -n

Repository: buihongduc132/opa-net

Length of output: 1919


Add a bounded timeout and reject non-2xx OTLP responses in src/audit/OtlpAuditSink.ts:54-70. write() is awaited on the deny/block path, so a slow collector can delay the response, and HTTP 4xx/5xx replies are currently treated as success because only thrown fetch failures are caught.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/audit/OtlpAuditSink.ts` around lines 54 - 70, Update OtlpAuditSink.write
to bound the fetch duration with an AbortController-based timeout, and validate
the response after fetch so non-2xx statuses throw and enter the existing error
logging path. Preserve the non-fatal behavior by continuing to catch timeout,
network, and HTTP-status failures without propagating them.

{
logRecords: [
{
timeUnixNano: String(Date.now() * 1_000_000),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,220p' src/audit/OtlpAuditSink.ts
printf '\n---\n'
rg -n "timeUnixNano|Date\.now\(\) \* 1_000_000|BigInt\(Date\.now\(\)\)" src

Repository: buihongduc132/opa-net

Length of output: 1919


Use a BigInt nanosecond timestamp here

Date.now() * 1_000_000 exceeds Number.MAX_SAFE_INTEGER, so the exported OTLP timestamp can be rounded before stringification. Use a BigInt-based nanosecond value instead, e.g. String(BigInt(Date.now()) * 1_000_000n).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/audit/OtlpAuditSink.ts` at line 104, Update the timeUnixNano assignment
in the OTLP audit export to compute nanoseconds with BigInt before
stringification, using BigInt(Date.now()) and a BigInt nanosecond multiplier to
avoid unsafe Number arithmetic.

Comment on lines +32 to +34
const OPA_BIN = process.env.OPA_BIN ?? '/home/bhd/.local/share/mise/installs/opa/1.18.2/opa';
const OPA_AVAILABLE = existsSync(OPA_BIN);
const SKIP_REASON = !OPA_AVAILABLE ? 'OPA binary not found' : '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether the same hardcoded-path convention already exists elsewhere,
# and how CI wires OPA_BIN for e2e tests.
rg -n 'OPA_BIN' tests/e2e/cli-contract.test.ts
rg -rn 'OPA_BIN' .github/workflows 2>/dev/null
fd -e yml -e yaml . .github/workflows --exec grep -l 'OPA_BIN' {} \;

Repository: buihongduc132/opa-net

Length of output: 1948


Replace the machine-specific OPA fallback

OPA_BIN should not default to /home/bhd/.local/share/mise/installs/opa/1.18.2/opa; on any other machine, this makes the e2e suite skip unless OPA_BIN is set. Use a PATH-based fallback instead, e.g. process.env.OPA_BIN ?? 'opa'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/block-rm-rf-dangerous-target.test.ts` around lines 32 - 34, Update
the OPA_BIN fallback used by the e2e test to use the PATH-resolved command name
“opa” instead of the machine-specific absolute path, while preserving the
OPA_AVAILABLE and SKIP_REASON behavior.

@buihongduc132
buihongduc132 merged commit a9a4e6e into main Jul 24, 2026
4 of 7 checks passed
@buihongduc132
buihongduc132 deleted the feat/reconcile-040-ghost branch July 24, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant