Claude/charming hamilton 2n l pc#311
Merged
Merged
Conversation
Recipe matcher rejected every scorecard-source finding (~310 ecosystem-
wide), routing them to :control "no safe fix available" advisories.
Root cause: `lib/recipe_matcher.ex` filtered candidate recipes with
`"*" in langs or language in langs`. Two failure modes:
1. 12 recipes declared `languages: ["any"]` — never matched, since
`"any"` is not a sentinel the filter recognises and no repo has
`"any"` as its primary language.
2. 8 scorecard / workflow-file recipes declared `languages: ["yaml"]`
— never matched, since yaml is a workflow-file type, not any
repo's primary language. So `recipe-pin-dependencies`,
`recipe-fix-workflow-permissions`, etc. were unreachable for SC013/
SC018 findings — the exact rule families dominating the daily
remediation sweep.
Fix:
- `langs_match?/2` private helper accepts `"*"` and `"any"` as
synonymous language-agnostic sentinels.
- `effective_language_for/2` remaps the lookup language to `"yaml"`
for patterns whose `source` is `"scorecard"` or whose `category`
names a known workflow-file rule family (DependencyPinning,
TokenPermissions, DangerousWorkflow, etc.). The repo's primary
language is irrelevant for workflow-file findings.
- Applied to `best_recipe/2`, `category_match_recipe/2`, and
`fuzzy_match_recipe/2`.
Tests pin all three invariants. All 22 scorecard recipe `fix_script`
references already exist on disk in `scripts/fix-scripts/` — the bug
was purely in matcher reachability, not missing fix implementations.
Closes the dispatcher half of the "no security stuff being sorted"
symptom. Remaining M7 work (PAT for cross-repo dispatch, push fixes
to remotes) still needs operator action, but the manifests will now
carry populated fix_script fields for scorecard findings.
The baseline had drifted into pure historical risk: 71 accepted findings (31 critical, 40 high) generated before the #278 stale-escript fix and the wave of code_safety/security_errors cleanups landed. A fresh scan against the current tree finds 35 findings, all medium-or-lower: - 32 low (code_safety hot-path expects, ncl_docker_not_podman, workflow_audit missing-workflow, structural_drift, etc.) - 3 medium (git_state transient + structural_drift) - 0 critical, 0 high Most old baseline entries are either: - fixed in code (e.g. the believe_me at src/abi/RuleEngine.idr is now inline-suppressed with a documented `-- hypatia: allow` directive), - migrated/refactored (e.g. lib/direct_github_pr.ex no longer exists), - or were covered by the new total-Python-ban / scanner-soundness wave. Net effect: every gate threshold of "fail on critical|high above baseline" now starts from an empty critical/high ledger — net-new critical or high findings will stand out, which is what the baseline is supposed to enable. Generated with the canonical Elixir escript pipeline against this tree (no rule changes, just a snapshot refresh). Severity threshold "low" so the snapshot reflects the full advisory surface, not just gates.
The HYPATIA_DISPATCH_PAT was provisioned with read access to
secret-scanning alerts, code-scanning alerts, and Dependabot alerts.
Only Dependabot was actually being consumed (lib/rules/dependabot_alerts.ex,
DA001-DA004) — the other two alert surfaces were granted but unused.
Adds two new rule modules mirroring the DependabotAlerts shape:
lib/rules/secret_scanning_alerts.ex (SSA001-SSA004)
SSA001 — Open leaked-secret alerts (always :critical; staleness
surfaced in the reason for triage prioritisation).
SSA002 — Repo-level meta-finding when any open alert exists.
SSA003 — Stale open alerts past the 7-day rotation threshold.
SSA004 — Resolved alerts with no documented resolution vocabulary
(anything outside revoked/used_in_tests/pattern_deleted/
pattern_edited).
lib/rules/code_scanning_alerts.ex (CSA001-CSA004)
CSA001 — Open code-scanning alerts (CodeQL + third-party SARIF
including Hypatia's own `hypatia` category). Severity
mapped from `security_severity_level`/`severity` onto the
canonical four-bucket scale.
CSA002 — Severity summary (any critical, ≥5 high, or ≥10 total).
CSA003 — Stale open alerts (3/7/30/90 days by severity bucket).
CSA004 — Dismissed without documented reason.
Wires both into `Hypatia.CLI`:
- registered in `@all_rule_modules` so the default scan includes them,
- scan blocks emit normalised findings alongside the rest,
- `format_module_name/1` gives them display names,
- usage strings updated to list the new --rules tokens.
Workflow comment in `.github/workflows/hypatia-scan.yml` updated to
note that the existing `security-events: write` grant now covers all
three alert APIs, not just Dependabot. No new permissions needed.
Tests pin token-absent behaviour and the non-GitHub-remote error path
for each module's helpers.
PR #278 documented that the deployed escript had been silently dropping the Elixir/Erlang/Coq/Lean/Agda/Zig/F*/Ada code_safety pattern families for days because the binary was stale relative to the rule sources. "No findings" looks identical whether the code is clean or the rule is broken — that ambiguity is the soundness gap. Closes it with the simplest possible mechanism: for every rule the scanner is supposed to detect, keep a known-bad sample on disk, and assert in CI that the rule fires on its sample at the expected severity. A rule that goes silent (regex drift, file pruning, packaging regression, module rename) breaks the build instead of silently weakening the estate's security posture. Layout: test/soundness/ manifest.json -- rule -> fixture -> severity fixtures/code_safety/ believe_me.idr -- Idris2 sorry.lean -- Lean admitted.v -- Coq unsafe_coerce.hs -- Haskell obj_magic_ocaml.ml -- OCaml getexn_on_external.res -- ReScript unwrap_without_check.rs -- Rust transmute.rs -- Rust unsafe elixir_system_shell.ex -- THE PR#278 false-negative elixir_os_cmd.ex -- Elixir os.cmd elixir_code_eval.ex -- Elixir Code.eval shell_download_then_run.sh -- curl|bash agda_postulate.agda -- Agda zig_ptr_cast.zig -- Zig README.adoc -- how to add a fixture test/soundness_test.exs -- runner, @moduletag :soundness Manifest entries cover all the language families PR #278 specifically called out as having been silently dropped. The runner is data-driven: adding a rule means dropping a fixture + a manifest entry, no test code change. Hand-run against the current tree: 14/14 fixtures fire at the expected severity. The soundness gate is operational. Out of scope (next iteration): - End-to-end escript-build soundness (build the escript, run it against the fixture corpus -- exact PR #278 reproduction). The in-process test catches rule-definition regressions, but a packaging regression that strips a module would still slip through. - Fixtures for non-code_safety families (workflow_audit, cicd_rules, structural_drift, scorecard, dependabot_alerts, ...).
The OutcomeTracker.verify_fix/3 re-scan mechanism existed but its result
was discarded on the success path: clean re-scans produced no marker,
unclean re-scans were re-recorded as :false_positive without preserving
the "this was verification, not an organic failure" distinction. The
outcomes log had no way to answer "what fraction of this recipe's
'successes' were actually verified clean by post-fix re-scan?"
That's the closed-loop metric this commit adds.
lib/outcome_tracker.ex
record_outcome/4,5
Optional `metadata` map merges into the record (under the canonical
fields so a caller can't overwrite recipe_id/repo/file/outcome/
timestamp/bot by accident).
record_and_verify/5
Now persists the verification verdict on every branch:
verified -> success record with "verification" = "verified"
still_present -> success record with "verification" = "still_present"
PLUS a follow-up :false_positive record
(caused_by = "post_fix_rescan")
scan_failed -> success record with "verification" = "scan_failed"
verify: false -> outcome record with "verification" = "unverified"
The distinction between "scan_failed" and "unverified" matters: a
recipe is not penalised for being run in environments without
panic-attack.
verification_rate/2
For a recipe_id, returns counts {verified, still_present,
scan_failed, unverified} and a rate = verified / (verified +
still_present). scan_failed and unverified records are excluded
from the denominator so a low-verification-attempt environment
doesn't artificially deflate the rate. Returns :insufficient_data
below min_attempts.
recipe_health/1
Aggregates across every recipe with recorded outcomes. Returns a
list of maps with dispatches / successes / failures / FPs /
success_rate / verification breakdown / status, sorted so the
most actionable rows (quarantine_candidate, degraded) surface
first. Configurable thresholds.
lib/mix/tasks/hypatia.recipe_health.ex
mix hypatia.recipe_health [--format json] [--only-actionable]
Prints the report in a human-readable table or JSON.
test/recipe_health_test.exs
Pins the rate calculation (verified/still_present ratio, scan_failed
+ unverified excluded), the insufficient_data threshold, and the
healthy/degraded/quarantine_candidate status mapping.
Hand-run against the current outcomes log: 4 recipes found, all flagged
:insufficient_data because the historical log was written before the
verification marker existed. From the next `record_and_verify`-enabled
dispatch onwards, recipes will accumulate verification data and migrate
to :healthy / :degraded / :quarantine_candidate based on real evidence.
…pper
Closes the gap where verification was opt-in only via record_and_verify
with explicit category/repo_path arguments — too inconvenient for the
gitbot-fleet bash runner to use, which is why the verification metric's
denominator was zero in the hand-run earlier.
OutcomeTracker.record_outcome_for_fix/4,5
Auto-derives `category` from the recipe registry (target_categories
field) and `repo_path` from $HYPATIA_REPOS_DIR/<repo>. Always
attempts re-scan verification on :success. Falls back gracefully
to "verification = scan_skipped" if the recipe isn't found, so
the outcome is still recorded and the gap is auditable.
mix hypatia.record_outcome
CLI wrapper for the bash dispatch-runner. Exit-code contract:
0 — recorded, verified-clean or scan_unavailable
2 — recorded but re-scan still finds the weak point (the runner
SHOULD treat the batch as failed and consider rollback)
1 — bad arguments / unrecoverable error
The non-zero exit on still_present is what lets bash notice a
false-fix without parsing JSON.
In-tree callers of record_outcome/4,5 stay as-is: learning_scheduler's
fleet-outcome replay and batch_rollback's mark-as-false-positive are
both legitimately unverified paths. The new entry point is for the
external runner; the docstring on record_and_verify now points to it.
Adds end-to-end packaging soundness — the half of the PR #278 fix the earlier in-process gate didn't cover. Builds the escript fresh, scans the fixtures tree with the built binary, asserts every manifest entry fires at the expected severity. Catches the failure mode where rule sources are correct but the escript build/packaging drops them. The gate caught a latent bug on its first end-to-end run: lib/hypatia/cli.ex:726 @language_extensions was missing .agda, .zig, .thy, .fst/.fsti, .adb/.ads. The patterns_for_language/1 dispatcher in lib/rules/code_safety.ex defines rules for agda/zig/isabelle/ fstar/ada — but because the CLI's directory walker had no extension-to-language mapping for those files, the rules NEVER FIRED on real scans. This is the exact PR #278 class: the engine knows the rule, the rule's regex works, but the wiring never gives the rule any input. Added all 7 missing language → extension mappings. Re-run shows agda_postulate and zig_ptr_cast (previously silent) now flag at the expected severity. test/soundness/run-escript-soundness.sh Builds escript, scans test/soundness/fixtures, asserts every manifest entry fires. Exits non-zero on the first regression with a "PR #278 class" diagnostic message pointing the reader at the escript build (mix.exs:escript, hypatia-cli.sh). .github/workflows/tests.yml New step "Escript packaging soundness" on the e2e-elixir job, after the existing E2E test suite. Re-uses the same setup-beam + cache + deps.get, no extra runtime cost beyond the escript build. Hand-run on the current tree: 14/14 fixtures fire at expected severity on the built escript.
Closes the third half of the closed-loop safety net: a recipe whose
post-fix re-scans are failing too often can no longer ship to repos
in :auto_execute mode. The dispatcher now consults the verification
rate before auto-executing and downgrades to :review (rhodibot PR for
human inspection) if the recipe is unhealthy.
OutcomeTracker.quarantined?/2
Cheap predicate derived from existing verification data — no new
GenServer or state. Returns true iff:
- verification rate < :threshold (default 0.30), AND
- verifiable-outcomes count >= :min_attempts (default 5)
Honours HYPATIA_RECIPE_QUARANTINE_DISABLE=true env override (logged
when used so audit history captures the bypass). Recipes with no
verification data are NOT quarantined — gating them would create a
chicken-and-egg where new recipes can never accumulate the data
needed to leave quarantine.
fleet_dispatcher.ex
do_eliminate_dispatch(:auto_execute, ...) now checks quarantined?
before dispatching to robot-repo-automaton. On quarantine, it
recurses with :review so rhodibot opens a PR instead. The fix gets
surfaced for human review; it doesn't get suppressed.
test/recipe_health_test.exs
Three new tests pin the invariants:
- quarantined? returns true on rate < 0.30 with >= 5 verifiable
- quarantined? returns false on insufficient data (chicken-and-egg)
- HYPATIA_RECIPE_QUARANTINE_DISABLE env override is honoured
Net effect: once `record_outcome_for_fix` is wired into the dispatch-
runner and verification data starts flowing, any recipe that drifts
toward false fixes silently becomes "review-only" without operator
intervention. The bad recipe can't damage the estate while waiting for
the human-review queue.
Investigation for follow-up #4 (soundness fixtures for non-code_safety families) revealed each rule family has architectural mismatches that make the "one fixture file per rule" pattern non-portable. Documenting honestly so future iteration starts from the right premise instead of re-discovering each blocker. Findings: cicd_rules/banned_language_file Unsuppressable by design (PR #280 "total ban, no exceptions"). A .py fixture in-tree produces a real critical finding in every scan, polluting the baseline. Needs either a policy carve-out for test/soundness/fixtures/ in the unsuppressable clause, or a separate scratch-repo scan-root model. Not done in this commit because both touch policy invariants that need a deliberate decision. workflow_audit, structural_drift, root_hygiene Operate at scan-root level (look for .github/workflows/, LICENSE, SECURITY.md at the root). Whole-tree scanning of the fixtures directory can't surface these — workflow_audit doesn't recurse into subdirs looking for .github/. Needs per-fixture scan-root. git_state, honest_completion Transient / git-state dependent — hermetic fixtures are hard. dependabot_alerts, secret_scanning_alerts, code_scanning_alerts GitHub API queries — no "known-bad sample on disk" model applies. Mock-based tests in test/*_alerts_test.exs already cover the token-absent + parse paths. Soundness gate doesn't extend here. README updated with a per-family table and a suggested Phase 2 design (extend manifest with `scan_root` field, scan per-fixture-directory instead of one tree-scan). When someone implements that, all the families above become tractable in one go. Net effect of #4: no new fixtures, but the README captures the architectural insight that would otherwise have to be re-discovered. The code_safety soundness gate from commits 74173ee + 6d40240 remains operational.
Phase 1, commit 1/4 of the watcher / supervision interface plan.
lib/hypatia/telemetry.ex
Centralised event-name registry. Eight events covering every
observable decision in the pipeline:
:scan, :complete (duration_ms, finding_count)
:dispatch, :decision (strategy, tier, recipe_id, repo)
:outcome, :recorded (recipe_id, repo, outcome, verification)
:verification, :result (recipe_id, repo, verdict)
:quarantine, :triggered (kind, id, reason, level)
:rate_limit, :exceeded (bot, scope)
:neural, :cycle (duration_ms)
:soundness, :violation (rule_module, rule_id)
Hand-written emit helpers per event (not meta-programmed) so each
call site shows what it's saying. `:telemetry.execute/3` is wrapped
in `safe_execute/3` so a missing `:telemetry` module (escript-only
builds, stripped releases) is a no-op rather than a crash —
instrumentation must never break the host.
`all_events/0` exposes the full list so the watcher / Prometheus
exporter / alerting layer can subscribe via attach_many.
Instrumented sites:
lib/hypatia/cli.ex — scan_complete with elapsed time
lib/fleet_dispatcher.ex — dispatch_decision on each tier (+
quarantine_triggered + downgrade
marker when auto_execute degrades
to review)
lib/outcome_tracker.ex — outcome_recorded on every write,
verification_result on every verify_fix,
quarantine_triggered when recipe
crosses verification-rate threshold
No new runtime dependency: :telemetry is already a transitive dep
of phoenix + bandit. Calls are no-ops when no handler is attached,
so this commit on its own changes nothing about runtime behaviour —
it just makes the upcoming watcher (commit 2/4), JSON API endpoint
(commit 3/4), and `mix hypatia.watch` TUI (commit 4/4) possible.
Refactored OutcomeTracker.verify_fix into a public telemetry-emitting
wrapper around the original `do_verify_fix` private impl, so the
verification event fires regardless of caller and the implementation
stays unchanged.
Phase 1, commit 2/4 of the watcher / supervision interface plan.
lib/hypatia/watcher.ex
GenServer that subscribes to every event in Hypatia.Telemetry.all_events/0
and maintains rolling-window counters in ETS so the CLI dashboard /
JSON API / future alerting layer can read live state without
re-parsing JSONL.
Three ETS tables, bucket-keyed for cheap pruning:
:hypatia_watcher_5m — 5min window, 5s buckets (60 buckets)
:hypatia_watcher_1h — 1hr window, 1min buckets (60 buckets)
:hypatia_watcher_1d — 1day window, 1hr buckets (24 buckets)
Public API:
Watcher.snapshot/0 full JSON-serialisable state
Watcher.counts/1 counts per window (cheap ETS read)
Watcher.recent_events/0 last N events per kind (drilldown)
Watcher.queue_depths/0 per-GenServer message_queue_len (5s poll)
Back-pressure: telemetry handler is a captured remote function
(&__MODULE__.handle_event/4) that casts to the watcher — the
producer process never pays the watcher's processing cost. If the
watcher's mailbox exceeds @max_mailbox (1000), incoming events are
DROPPED and counted as :dropped_events instead of building up.
This keeps the watcher from becoming a tarpit during sweep storms
(e.g. the burst of ~20 hypatia-security-alert dispatches we just
saw in gitbot-fleet).
Lifecycle: supervised by Hypatia.Application (added at Layer 0.8,
after the existing Diagnostics.Monitor). ETS tables die with the
process — live state is ephemeral by design (Phase 1 scope);
persistence to verisim-data is Phase 3.
lib/application.ex
Wires Hypatia.Watcher into the supervision tree.
test/watcher_test.exs
Five tests:
- scan_complete event increments the m5 counter
- dispatch_decision event lands in all three windows
- snapshot/0 returns the documented shape
- recent_events captures latest with measurements + metadata
- queue_depths returns a map (content depends on whether
Hypatia.Supervisor is up)
Hand-smoketested end-to-end: three telemetry calls produced three
counted events across all windows, zero dropped, recent-event tail
populated with the right metadata.
Phase 1, commit 3/4 of the watcher / supervision interface plan.
lib/hypatia/web/api_router.ex (new)
Forwarded from /api by Hypatia.Web.Router. Three endpoints:
GET /api/status full Watcher.snapshot() with event
keys flattened to dotted strings
for JSON-friendliness
GET /api/counts/:window cheap event-count read (5m|1h|1d),
bypasses the GenServer and goes
straight to ETS — usable as a
Prometheus polling target
GET /api/recipes recipe-health roll-up; optional
?status=quarantine_candidate,degraded
filter for actionable rows only
Loopback-only by default — `loopback_only/2` plug returns 403 to
any non-127.0.0.1 / non-::1 caller. Operational data (queue
depths, recipe verification rates, recent telemetry events) must
not leak past the local machine. HYPATIA_API_ALLOW_NONLOCAL=true
bypasses the gate, logged on every request so audit history
captures the bypass.
lib/hypatia/web/router.ex
Forwards /api to ApiRouter. /health stays publicly reachable so
container orchestrators and load balancers can liveness-probe
without a tunnel.
test/api_router_test.exs
Plug.Test-based unit tests covering:
- loopback gate accepts 127.0.0.1, rejects 10.x with 403
- env override bypass works
- /status returns dotted event-key strings (not JSON arrays)
- /counts/:window accepts 5m/1h/1d, 400s on unknown
- /recipes returns rows; ?status= filter validates atom names
- unknown /api/* path returns 404 JSON
No new runtime dep — Plug.Test is part of the existing Plug dep.
Both new modules parse cleanly; compile-check deferred to CI
(local build path doesn't have :plug, but the Mix project does
via the existing dependency declaration).
Phase 1, commit 4/4 of the watcher / supervision interface plan.
lib/mix/tasks/hypatia.watch.ex
Terminal dashboard backed by Hypatia.Watcher. No external deps —
uses IO.ANSI for cursor positioning so it works over plain SSH
with zero terminfo/curses requirements.
Two operating modes:
Local attaches to Watcher in the same BEAM (default)
Remote polls http://127.0.0.1:9090/api/status (via --url)
Modes are interchangeable — same snapshot shape from either source.
--url makes it possible to watch a remote Hypatia via an SSH
tunnel without spinning up a local node.
Display (refresh every 2s by default):
- Uptime
- Event counts in the 5min + 1hr windows, sorted by count
- GenServer queue depths (yellow > 10, red > 100)
- Dropped-event warning when back-pressure has kicked in
- Last-updated timestamp
Flags:
--interval SECONDS refresh rate (default 2)
--url URL poll HTTP /api/status instead of local
--once render once and exit (good for cron)
--plain suppress ANSI cursor (pipe-safe)
test/watch_task_test.exs
Three tests via ExUnit.CaptureIO:
- render/3 produces dotted-string event names in the output
- :unavailable snapshot shows the actionable error message
- dropped_events > 0 fires the back-pressure warning
render/3 is exposed publicly (was defp) so the test can exercise
the formatting end-to-end without going through Mix.Task plumbing.
Smoke-tested against a real Watcher with all 5 instrumented event
kinds; output renders cleanly with bold headers, dim dividers,
aligned counters, and the expected colour coding.
This closes Phase 1 of the watcher / supervision plan:
1/4 ✓ telemetry instrumentation (d0ddd2f)
2/4 ✓ Watcher GenServer + ETS aggregator (3b4379e)
3/4 ✓ /api/* loopback-only endpoints (30ced35)
4/4 ✓ mix hypatia.watch CLI (this commit)
Phase 2 (web dashboard + SSE stream + Prometheus endpoint) and
Phase 3 (alerts + persistence + anomaly detection) remain.
🔍 Hypatia Security ScanFindings: 32 issues detected
View findings[
{
"reason": "Js.Dict deprecated -- use Dict (2 occurrences)",
"type": "deprecated_api",
"file": "/home/runner/work/hypatia/hypatia/test/soundness/fixtures/code_safety/getexn_on_external.res",
"action": "module_replace",
"rule_module": "migration_rules",
"severity": "high"
},
{
"reason": "Repository has 2 non-main remote branch(es). Policy: single main branch only.",
"type": "GS007",
"file": ".",
"action": "delete_remote_branches",
"rule_module": "git_state",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": ".github/workflows/dependabot-automerge.yml",
"action": "update",
"rule_module": "code_scanning_alerts",
"severity": "high"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": ".github/workflows/hypatia-scan.yml",
"action": "update",
"rule_module": "code_scanning_alerts",
"severity": "high"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": "test/soundness/fixtures/code_safety/getexn_on_external.res",
"action": "update",
"rule_module": "code_scanning_alerts",
"severity": "high"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": ".github/workflows/dependabot-automerge.yml",
"action": "update",
"rule_module": "code_scanning_alerts",
"severity": "high"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": "hyperpolymath/hypatia",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": "adapters/src/main.rs",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": ".github/workflows/docs.yml",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/code_scanning_alerts/CSA001 -- Hypatia code_scanning_alerts: CSA001 -- 0 day(s) old",
"type": "CSA001",
"file": ".github/workflows/dependabot-auto-merge.yml",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.