Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ workflows:
- 'dtolnay/rust-toolchain@master'
- 'github/codeql-action@v4.37.8'
- 'gitleaks/gitleaks-action@v3.0.0'
- 'returntocorp/semgrep-action@v1'
- 'taiki-e/install-action@v2.86.7'
- 'trufflesecurity/trufflehog@v3.97.1'
'.github/workflows/tests.yml':
Expand Down Expand Up @@ -305,16 +304,6 @@ dependencies:
commit: 'sha1-c74f04c77a36247a813493945e803178b93d170f'
owner_id: 6759885
repo_id: 1275650185
'hyperpolymath/smtp-notify-action@v0.2.0':
ref: 'v0.2.0'
commit: 'sha1-ede1191ef6ff3ac02c4f4d9efdf837ee517e11d7'
owner_id: 6759885
repo_id: 1352485172
'returntocorp/semgrep-action@v1':
ref: 'v1'
commit: 'sha1-713efdd345f3035192eaa63f56867b88e63e4e5d'
owner_id: 147861678
repo_id: 715166645
'ruby/setup-ruby@v1.321.0':
ref: 'v1.321.0'
commit: 'sha1-95ef2b042f9d7a56d8268cba8559e2842e2ad01b'
Expand Down
63 changes: 0 additions & 63 deletions .github/workflows/security-policy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,37 +103,6 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# ============================================================================
# SAST Scanning
# ============================================================================

semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v7.0.1

- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/rust
p/elixir
p/security-audit
p/secrets
args: --sarif --output=semgrep.sarif

- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v4.37.8
if: always()
with:
sarif_file: semgrep.sarif

codeql:
name: CodeQL Analysis
runs-on: ubuntu-latest
Expand Down Expand Up @@ -237,7 +206,6 @@ jobs:
- rust-audit
- rust-deny
- secret-scan
- semgrep
- codeql
- sbom-rust
if: always()
Expand All @@ -251,7 +219,6 @@ jobs:
["rust-audit"]="${{ needs.rust-audit.result }}"
["rust-deny"]="${{ needs.rust-deny.result }}"
["secret-scan"]="${{ needs.secret-scan.result }}"
["semgrep"]="${{ needs.semgrep.result }}"
["codeql"]="${{ needs.codeql.result }}"
["sbom-rust"]="${{ needs.sbom-rust.result }}"
)
Expand Down Expand Up @@ -564,34 +531,6 @@ jobs:
with:
category: "/language:${{matrix.language}}"

audit_semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v7.0.1

- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/rust
p/security-audit
p/secrets
p/dockerfile
p/supply-chain
args: --sarif --output=semgrep.sarif

- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v4.37.8
if: always()
with:
sarif_file: semgrep.sarif

# ============================================================================
# License Compliance
# ============================================================================
Expand Down Expand Up @@ -716,7 +655,6 @@ jobs:
- gitleaks
- trufflehog
- audit_codeql
- audit_semgrep
- license-check
- sbom-generation
if: always()
Expand Down Expand Up @@ -745,7 +683,6 @@ jobs:
echo "| Gitleaks | $(status_icon '${{ needs.gitleaks.result }}') ${{ needs.gitleaks.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| TruffleHog | $(status_icon '${{ needs.trufflehog.result }}') ${{ needs.trufflehog.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| CodeQL | $(status_icon '${{ needs.audit_codeql.result }}') ${{ needs.audit_codeql.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Semgrep | $(status_icon '${{ needs.audit_semgrep.result }}') ${{ needs.audit_semgrep.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| License Check | $(status_icon '${{ needs.license-check.result }}') ${{ needs.license-check.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| SBOM Generation | $(status_icon '${{ needs.sbom-generation.result }}') ${{ needs.sbom-generation.result }} |" >> $GITHUB_STEP_SUMMARY

Expand Down
150 changes: 73 additions & 77 deletions lib/fleet_dispatcher.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,54 +45,6 @@ defmodule Hypatia.FleetDispatcher do
end
end

# Standard fleet dispatch path for eliminate tier.
defp dispatch_eliminate_via_fleet(recipe, pattern) do
confidence = Map.get(recipe, "confidence", 0.0)
strategy = TriangleRouter.dispatch_strategy(confidence)

bot_id =
case strategy do
:auto_execute -> "robot-repo-automaton"
:review -> "rhodibot"
:report_only -> "sustainabot"
end

action_type =
case strategy do
:auto_execute -> :commit_push
:review -> :pr_create
:report_only -> :advisory
end

# Gate review -- every action must pass through the Kin Gate
gate_action = %{
bot_id: bot_id,
repo: get_pattern_repo(pattern),
action_type: action_type,
confidence: confidence,
pattern_id: Map.get(pattern, "id", Map.get(pattern, "description", "")),
scan_timestamp: Map.get(pattern, "scan_timestamp"),
dispatch_tier: strategy
}

case gate_review(gate_action) do
{:approved, _} ->
do_eliminate_dispatch(strategy, recipe, pattern, confidence)

{:held, reason} ->
Logger.warning("Gate held eliminate dispatch: #{reason}")
{:ok, :held}

{:rejected, reason} ->
Logger.warning("Gate rejected eliminate dispatch: #{reason}")
{:error, :gate_rejected, reason}

{:deferred, wait_ms} ->
Logger.info("Gate deferred eliminate dispatch -- retry in #{div(wait_ms, 1000)}s")
{:ok, :deferred}
end
end

def dispatch_routed_action({:substitute, recipe, pattern}) do
proven_module = Map.get(recipe, "proven_module", "unknown")

Expand Down Expand Up @@ -123,22 +75,20 @@ defmodule Hypatia.FleetDispatcher do
})
end

@doc """
Dispatch a ProofObligation recipe through the Safety Triangle.

Called by `ProofObligation.obligations_from_patterns/2` and any code
that constructs `{:proof_obligation, recipe, pattern}` tuples.

Triangle routing for proof obligations:
- `:eliminate` (auto-provable, confidence >= 0.90) →
robot-repo-automaton applies tactic inline
- `:eliminate` (confidence < 0.90) →
echidnabot with eliminate-tier hint
- `:substitute` →
echidnabot with VeriSimDB-recommended prover hint
- `:control` →
sustainabot advisory (sorry/Admitted present, human required)
"""
# Dispatch a ProofObligation recipe through the Safety Triangle.
#
# Called by `ProofObligation.obligations_from_patterns/2` and any code
# that constructs `{:proof_obligation, recipe, pattern}` tuples.
#
# Triangle routing for proof obligations:
# - `:eliminate` (auto-provable, confidence >= 0.90) ->
# robot-repo-automaton applies tactic inline
# - `:eliminate` (confidence < 0.90) ->
# echidnabot with eliminate-tier hint
# - `:substitute` ->
# echidnabot with VeriSimDB-recommended prover hint
# - `:control` ->
# sustainabot advisory (sorry/Admitted present, human required)
def dispatch_routed_action({:proof_obligation, recipe, pattern}) do
tier = Map.get(recipe, "triangle_tier", "substitute")
claim = Map.get(recipe, "claim", Map.get(pattern, "description", ""))
Expand Down Expand Up @@ -202,19 +152,17 @@ defmodule Hypatia.FleetDispatcher do
end
end

@doc """
Dispatch a DependabotAlerts recipe through the Safety Triangle.

Called by `DependabotAlerts.fixes_from_alerts/3` and any code that
constructs `{:dependabot_fix, recipe, pattern}` tuples.

Triangle routing for Dependabot alerts:
- `:eliminate` + confidence >= 0.95 -> robot-repo-automaton auto-bumps
(subject to Kin Gate, rate limiter, exclusion registry)
- `:eliminate` + confidence in [0.85, 0.95) -> rhodibot opens a PR
- `:substitute` -> rhodibot opens a PR (major bump / breaking change)
- `:control` -> sustainabot advisory (no auto-fix path)
"""
# Dispatch a DependabotAlerts recipe through the Safety Triangle.
#
# Called by `DependabotAlerts.fixes_from_alerts/3` and any code that
# constructs `{:dependabot_fix, recipe, pattern}` tuples.
#
# Triangle routing for Dependabot alerts:
# - `:eliminate` + confidence >= 0.95 -> robot-repo-automaton auto-bumps
# (subject to Kin Gate, rate limiter, exclusion registry)
# - `:eliminate` + confidence in [0.85, 0.95) -> rhodibot opens a PR
# - `:substitute` -> rhodibot opens a PR (major bump / breaking change)
# - `:control` -> sustainabot advisory (no auto-fix path)
def dispatch_routed_action({:dependabot_fix, recipe, pattern}) do
tier = Map.get(recipe, "triangle_tier", "control")
confidence = Map.get(recipe, "confidence", 0.5)
Expand Down Expand Up @@ -271,6 +219,54 @@ defmodule Hypatia.FleetDispatcher do

# --- Eliminate dispatch helpers (called after Gate approval) ---

# Standard fleet dispatch path for eliminate tier.
defp dispatch_eliminate_via_fleet(recipe, pattern) do
confidence = Map.get(recipe, "confidence", 0.0)
strategy = TriangleRouter.dispatch_strategy(confidence)

bot_id =
case strategy do
:auto_execute -> "robot-repo-automaton"
:review -> "rhodibot"
:report_only -> "sustainabot"
end

action_type =
case strategy do
:auto_execute -> :commit_push
:review -> :pr_create
:report_only -> :advisory
end

# Gate review -- every action must pass through the Kin Gate
gate_action = %{
bot_id: bot_id,
repo: get_pattern_repo(pattern),
action_type: action_type,
confidence: confidence,
pattern_id: Map.get(pattern, "id", Map.get(pattern, "description", "")),
scan_timestamp: Map.get(pattern, "scan_timestamp"),
dispatch_tier: strategy
}

case gate_review(gate_action) do
{:approved, _} ->
do_eliminate_dispatch(strategy, recipe, pattern, confidence)

{:held, reason} ->
Logger.warning("Gate held eliminate dispatch: #{reason}")
{:ok, :held}

{:rejected, reason} ->
Logger.warning("Gate rejected eliminate dispatch: #{reason}")
{:error, :gate_rejected, reason}

{:deferred, wait_ms} ->
Logger.info("Gate deferred eliminate dispatch -- retry in #{div(wait_ms, 1000)}s")
{:ok, :deferred}
end
end

defp do_eliminate_dispatch(:auto_execute, recipe, pattern, confidence) do
recipe_id = Map.get(recipe, "id")

Expand Down
4 changes: 2 additions & 2 deletions lib/hypatia/diagnostics/monitor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,12 @@ defmodule Hypatia.Diagnostics.Monitor do
nil -> {:error, :neural_unresponsive}
status -> {:ok, {:neural, status}}
end
rescue
_ -> {:error, :neural_crashed}
catch
# Training cycles can take minutes -- a timeout means busy, not crashed
:exit, {:timeout, _} -> {:ok, {:neural, :training_in_progress}}
:exit, _ -> {:error, :neural_crashed}
rescue
_ -> {:error, :neural_crashed}
end
end

Expand Down
Loading
Loading