Back to Blog
Security March 16, 2026 | 10 min read

Pre-Commit Security Gates: Catching Vulnerabilities Before They Land

9 blocking pillars that guard every commit to the repository

Prismatic Engineering

Prismatic Platform

The Pre-Commit Philosophy


Code review catches bugs after they are written. CI pipelines catch them

after they are pushed. Pre-commit hooks catch them before they are even

committed. The earlier a problem is detected, the cheaper it is to fix.

A developer who gets immediate feedback while the change is fresh in their

mind fixes issues in seconds rather than context-switching back hours later.


The Prismatic pre-commit system enforces 9 blocking pillars that must pass

before any commit is accepted. Each pillar targets a specific class of

defects that, if allowed into the codebase, would compound over time.


The 9 Blocking Pillars


PillarFocusDetection Method

|--------|-------|-----------------|

ZERORuntime safetyGrep for String.to_atom, bare rescue, unsafe binary_to_term SEALSecurityGrep for SQL injection, hardcoded secrets, Code.eval PERFPerformanceGrep for length()==0, unbounded Repo.all, N+1 patterns HYGIENERepository cleanlinessFile size limits, binary detection, naming conventions NMNDCode qualityNo stubs, no task markers in lib/, no placeholders TACHTest coverageEvery changed lib/*.ex must have a corresponding test file DOCSDocumentation@moduledoc, @doc, and @spec required on public functions DEPSDependenciesVersion constraints, no unstable git branches RDMEREADME presenceEvery umbrella app must have a README.md

Grep-Based Fast Scanning


The first phase of pre-commit validation uses grep to scan staged file

content for banned patterns. This approach was chosen for three reasons:

speed (completes in under 2 seconds), reliability (no compilation needed),

and simplicity (patterns are maintainable regex strings).


The hook extracts staged content using git diff --cached --name-only

to identify changed files, then git show :path to read the staged

version of each file. This ensures the hook checks what will actually

be committed, not the working directory state.



# Example: ZERO pillar checks

staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep '.ex$')

for file in $staged_files; do

content=$(git show ":$file")

if echo "$content" | grep -n 'String.to_atom(' > /dev/null; then

echo "ZERO VIOLATION: String.to_atom found in $file"

exit 1

fi

done


Mix Task Integration


The second phase runs mix tasks for checks that require compilation

or deeper analysis:


mix format --check-formatted ensures all staged files conform to

the project's formatting rules. This eliminates style debates in code

review and keeps diffs clean.


mix compile --warnings-as-errors --force catches compilation warnings

that could indicate logic errors, unused variables, or deprecated function

calls. The --force flag ensures fresh compilation of all changed modules.


mix truth.validate runs the NCLB (No Claim Left Behind) validation

pipeline, ensuring all platform statistics and claims in documentation

are backed by verifiable evidence from the live codebase.


mix credo --mute-exit-status runs as an advisory check. Credo findings

are reported but do not block the commit, allowing developers to address

style suggestions at their discretion.


Advisory vs. Blocking Enforcement


Not all checks warrant blocking a commit. The system distinguishes between

blocking checks (violations prevent the commit) and advisory checks

(violations are reported but the commit proceeds). This distinction is

critical for developer productivity.


Blocking enforcement is reserved for issues that are objectively wrong:

security vulnerabilities, missing test files, runtime crash risks. Advisory

enforcement covers stylistic preferences and aspirational quality targets

like property-based testing coverage.


The CI pipeline applies the full 17-pillar doctrine validation using

mix check.doctrines, which includes additional checks for OTEL

(observability), GITL (conventional commit format), KNOW (knowledge

coverage), and other pillars that are too slow or context-dependent

for pre-commit enforcement.


Performance Characteristics


The complete pre-commit pipeline executes in under 10 seconds for typical

commits affecting 1-15 files. The grep phase completes in 1-2 seconds,

format checking takes 2-3 seconds, and compilation with warnings takes

3-5 seconds. For larger commits, the pipeline scales linearly with the

number of changed files.


The hook is implemented as a bash script that runs checks sequentially,

failing fast on the first blocking violation. This means developers

get feedback on the most critical issue immediately rather than waiting

for all checks to complete.


Tags

pre-commit security doctrine enforcement ci-cd quality