chore: add AI-drift guardrails per Zornek article
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m31s
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m31s
- Enable key Jump credo checks: TestHasNoAssertions, VacuousTest, WeakAssertion, UnusedLiveViewAssign, UndeclaredExternalResource, AssertReceiveTimeout - Add mix xref graph --label compile-connected --fail-above 4 - Add --warnings-as-errors to mix test step - Add sobelow and mix_audit deps; wire into audit CI target
This commit is contained in:
parent
d31e783776
commit
3e51e62a8b
4 changed files with 50 additions and 25 deletions
35
.credo.exs
35
.credo.exs
|
|
@ -189,26 +189,21 @@
|
|||
#
|
||||
## Jump Credo Checks
|
||||
#
|
||||
{Jump.CredoChecks.AssertElementSelectorCanNeverFail, []}
|
||||
# {Jump.CredoChecks.AssertReceiveTimeout, []},
|
||||
# {Jump.CredoChecks.AvoidFunctionLevelElse, []},
|
||||
# {Jump.CredoChecks.AvoidLoggerConfigureInTest, []},
|
||||
# {Jump.CredoChecks.AvoidSocketAssignsInTest, []},
|
||||
# {Jump.CredoChecks.ConditionalAssertion, []},
|
||||
# {Jump.CredoChecks.DoctestIExExamples, []},
|
||||
# {Jump.CredoChecks.ForbiddenFunction, []},
|
||||
# {Jump.CredoChecks.LiveViewFormCanBeRehydrated, []},
|
||||
# {Jump.CredoChecks.UndeclaredExternalResource, []},
|
||||
# {Jump.CredoChecks.PreferChangeOverUpDownMigrations, [start_after: "0"]},
|
||||
# {Jump.CredoChecks.PreferTextColumns, [start_after: "0"]},
|
||||
# {Jump.CredoChecks.SafeBinaryToTerm, []},
|
||||
# {Jump.CredoChecks.TestHasNoAssertions, []},
|
||||
# {Jump.CredoChecks.TooManyAssertions, []},
|
||||
# {Jump.CredoChecks.TopLevelAliasImportRequire, []},
|
||||
# {Jump.CredoChecks.UnusedLiveViewAssign, []},
|
||||
# {Jump.CredoChecks.UseObanProWorker, []},
|
||||
# {Jump.CredoChecks.VacuousTest, []},
|
||||
# {Jump.CredoChecks.WeakAssertion, []}
|
||||
{Jump.CredoChecks.AssertElementSelectorCanNeverFail, []},
|
||||
# Catch tests that run green without proving anything.
|
||||
# Directly addresses the AI drift of writing tests that pass but don't
|
||||
# verify behavior — the false confidence Mike Zornek warns about.
|
||||
{Jump.CredoChecks.TestHasNoAssertions, []},
|
||||
{Jump.CredoChecks.VacuousTest, []},
|
||||
{Jump.CredoChecks.WeakAssertion, []},
|
||||
# Catch LiveView assigns that are set but never rendered — a common
|
||||
# pattern in AI-generated templates.
|
||||
{Jump.CredoChecks.UnusedLiveViewAssign, []},
|
||||
# Ensure references to external resources (images, fonts, static
|
||||
# assets) are declared so the build system knows about them.
|
||||
{Jump.CredoChecks.UndeclaredExternalResource, []},
|
||||
# Catch tests relying on fragile timing assumptions.
|
||||
{Jump.CredoChecks.AssertReceiveTimeout, []}
|
||||
],
|
||||
disabled: [
|
||||
#
|
||||
|
|
|
|||
30
Makefile
30
Makefile
|
|
@ -1,32 +1,52 @@
|
|||
.PHONY: precommit format test deps credo audit hex-audit cargo-audit
|
||||
.PHONY: precommit format test deps credo xref audit hex-audit cargo-audit deps-audit sobelow
|
||||
|
||||
# Runs every code-quality check from Mike Zornek's "Guarding Against AI Drift"
|
||||
# article in one shot. The agent and CI both gate on this alias.
|
||||
precommit:
|
||||
@EXIT=0; \
|
||||
$(MAKE) format || EXIT=1; \
|
||||
$(MAKE) test || EXIT=1; \
|
||||
$(MAKE) deps || EXIT=1; \
|
||||
$(MAKE) credo || EXIT=1; \
|
||||
$(MAKE) xref || EXIT=1; \
|
||||
exit $$EXIT
|
||||
|
||||
# Security audit targets — run independently (network-dependent, not in precommit).
|
||||
# Add these to CI pipeline in addition to precommit.
|
||||
|
||||
audit: hex-audit cargo-audit
|
||||
# Per Zornek: security scanning lives in its own CI job so a red mark there clearly
|
||||
# means "a dependency needs attention" rather than "your own code has a style problem."
|
||||
audit: hex-audit cargo-audit deps-audit sobelow
|
||||
|
||||
hex-audit:
|
||||
MIX_ENV=test mix hex.audit
|
||||
|
||||
deps-audit:
|
||||
MIX_ENV=test mix deps.audit
|
||||
|
||||
cargo-audit:
|
||||
cargo audit --file rust/prop_grid_rs/Cargo.lock
|
||||
|
||||
sobelow:
|
||||
MIX_ENV=test mix sobelow --config --quiet
|
||||
|
||||
format:
|
||||
MIX_ENV=test mix format --check-formatted
|
||||
|
||||
test:
|
||||
MIX_ENV=test mix test
|
||||
MIX_ENV=test mix test --warnings-as-errors
|
||||
|
||||
deps:
|
||||
MIX_ENV=test mix deps.unlock --check-unused
|
||||
|
||||
credo:
|
||||
MIX_ENV=test mix credo --strict
|
||||
|
||||
# Catches compile-time coupling creep. Fails if a change introduces new
|
||||
# compile-time dependencies between modules (which balloon recompile times).
|
||||
# Baselines at the current 4 pre-existing LiveView→band_config deps.
|
||||
xref:
|
||||
MIX_ENV=test mix xref graph --label compile-connected --fail-above 4
|
||||
|
||||
# Security-focused static analysis for Phoenix apps. Catches XSS, CSRF,
|
||||
# insecure config, and other common web vulnerabilities.
|
||||
sobelow:
|
||||
MIX_ENV=test mix sobelow --config --quiet
|
||||
|
|
|
|||
6
mix.exs
6
mix.exs
|
|
@ -99,6 +99,12 @@ defmodule Microwaveprop.MixProject do
|
|||
{:oban_web, "~> 2.12", path: "vendor/oban_web", override: true},
|
||||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||
{:jump_credo_checks, "~> 0.4", only: [:dev, :test], runtime: false},
|
||||
# Security scanning for Phoenix apps — flags common vulnerabilities
|
||||
# like XSS, CSRF, and insecure config patterns.
|
||||
{:sobelow, "~> 0.13", only: [:dev, :test], runtime: false},
|
||||
# Cross-references locked deps against community security advisories
|
||||
# so CVEs in transitive deps don't go unnoticed.
|
||||
{:mix_audit, "~> 2.0", only: [:dev, :test], runtime: false},
|
||||
{:nx, "~> 0.13", only: [:dev, :test]},
|
||||
{:axon, "~> 0.7", only: [:dev, :test]},
|
||||
{:exla, "~> 0.9", only: [:dev, :test]},
|
||||
|
|
|
|||
4
mix.lock
4
mix.lock
|
|
@ -39,6 +39,7 @@
|
|||
"mdex_native": {:hex, :mdex_native, "0.2.6", "16c0d9ffca05990982ef8113c0a61950ffc250bf0792e17b95b28b74e1f572dc", [:mix], [{:rustler, "~> 0.32", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.8", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "eaaf2af27162c9879f5aef66344101dadf1898e71ea6ac9eb811c8d92d8e49ad"},
|
||||
"mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
|
||||
"mint": {:hex, :mint, "1.9.3", "3337184d69179695c7a9f1714d92c11e629d36c8c037a21cf490131d3d150554", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5f7c9342480c069dbbc4eeac3490303c9e01870ff01a7f1d29b6107054fc1e74"},
|
||||
"mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"},
|
||||
"mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
|
||||
"msgpax": {:hex, :msgpax, "2.4.0", "4647575c87cb0c43b93266438242c21f71f196cafa268f45f91498541148c15d", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "ca933891b0e7075701a17507c61642bf6e0407bb244040d5d0a58597a06369d2"},
|
||||
"nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"},
|
||||
|
|
@ -71,6 +72,7 @@
|
|||
"req": {:hex, :req, "0.6.3", "7fe5e68792ff0546e45d5919104fa1764a13694cfe3e48c8a0f32ad051ae77e4", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "e85b5c6c990e6c3f52bbba68e6f099118f2b8252825f96c7c3636b97a3de307d"},
|
||||
"rewrite": {:hex, :rewrite, "1.3.0", "67448ba7975690b35ba7e7f35717efcce317dbd5963cb0577aa7325c1923121a", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "d111ac7ff3a58a802ef4f193bbd1831e00a9c57b33276e5068e8390a212714a5"},
|
||||
"rustler_precompiled": {:hex, :rustler_precompiled, "0.9.0", "3a052eda09f3d2436364645cc1f13279cf95db310eb0c17b0d8f25484b233aa0", [:mix], [{:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "471d97315bd3bf7b64623418b3693eedd8e47de3d1cb79a0ac8f9da7d770d94c"},
|
||||
"sobelow": {:hex, :sobelow, "0.14.1", "2f81e8632f15574cba2402bcddff5497b413c01e6f094bc0ab94e83c2f74db81", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8fac9a2bd90fdc4b15d6fca6e1608efb7f7c600fa75800813b794ee9364c87f2"},
|
||||
"sourceror": {:hex, :sourceror, "1.12.2", "85bfd48159f020c0cbfc72f289f11456fdc05dc43719b6f2589fb969faefa113", [:mix], [], "hexpm", "da37d3da09c5b890528802c7056a8f585a061973820d7656b6e3649c14f0e9cb"},
|
||||
"spitfire": {:hex, :spitfire, "0.3.13", "edd207b065eaec57acc5484097d0aa3e97fe4246168c54e67a9af040b8dee4c1", [:mix], [], "hexpm", "3601be88ceed4967b584e96444de3e1d12d6555ae0864a7390b9cd5332d134b4"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
|
|
@ -91,4 +93,6 @@
|
|||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.6.0", "73db5ab8aaefd1a876a97ce3e6afc96562625de69ef17a4e04426e034849d0b8", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "50021a85bce8f203b086705d9e0c5415e2c7eb05d319111b0428fe71f9934617"},
|
||||
"xla": {:hex, :xla, "0.10.0", "41121e9f011456242d3a79b9289910ce43419be0b0e7ebe67cc1292c6b3f232f", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f57d91aea6e661b52bf12239316c598679e9170628122bbd941235f040122bc6"},
|
||||
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
|
||||
"yaml_elixir": {:hex, :yaml_elixir, "2.12.2", "9dd1330fb4cd9a36a7b0f502e5b12486eff632792ee4a5f0eba52a4d4ec32c9c", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "e7c1b10122f973e6558462d51c39026ba0e14afbc6745318e990ea82cfe9e159"},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue