Skip to content

fix(review): features.safety is per-repo disableable via .gittensory.yml even when the operator enabled it globally #2269

Description

@JSONbored

Parent: #1936

Problem

resolveConvergedFeature's precedence for the safety feature (prompt-injection defanging) is: global env kill-switch (off → always false) → per-repo features.safety override (true/false) → allowlist default. This means a repo owner (or anyone with push access to a repo, since .gittensory.yml lives in the repo and only the file change itself is guardrailed for manual review, not the content of a safety-relevant features: block) can set features.safety: false in their own config, disabling defangReviewInput's prompt-injection defense for that repo's PR title/body/diff before it reaches the AI reviewer — even though the operator turned the safety feature on globally, intending it to apply everywhere. This is distinct from secret_leak, which is confirmed unconditional and cannot be disabled per-repo.

Failure scenario: an operator running self-hosted gittensory across many repos turns on the safety feature globally to protect every repo's AI reviewer from prompt-injection payloads embedded in a hostile PR title/body/diff. A repo owner (who may not be the operator in a multi-tenant self-host, or whose repo an attacker has push access to) sets features.safety: false in that repo's .gittensory.yml. A crafted PR title/body can now attempt to manipulate the AI reviewer's verdict without the defanging defense on that repo specifically, with no warning surfaced to the operator that a repo opted out of a protection they believed was instance-wide.

Requirements

  • A security-critical feature the operator enables globally must not be silently overridable to "off" by a per-repo config a lower-trust actor controls.
  • The fix should stay config-driven (this codebase's convention) — it should scope to security-relevant features specifically, not remove per-repo flexibility for non-security converged features (rag/reputation/unifiedComment).

Deliverables

  • Invert precedence for safety specifically so a per-repo override can only tighten (force-on) not loosen (force-off) an operator's global enablement — mirroring how secret_leak is already unconditional.
  • At minimum (if inversion is judged too disruptive), emit a structured warning/audit_events entry when a repo's manifest disables an operator-enabled safety-critical feature, so operators monitoring the fleet can detect the opt-out.
  • Add a regression test: operator enables safety globally, a repo's .gittensory.yml sets features.safety: false — assert the defense stays active (or, for the warning-only variant, assert the opt-out is recorded/surfaced).

Acceptance criteria

  • An operator's global enablement of the safety feature can no longer be silently defeated by a single repo's config.
  • Non-security converged features (rag/reputation/unifiedComment) retain their existing per-repo override flexibility, unaffected by this change.

Expected outcome

An operator's instance-wide prompt-injection defense actually applies instance-wide, closing a path where a lower-trust repo-level actor could quietly weaken a security control the operator explicitly turned on.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions