<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Navesz</title>
    <description>The latest articles on DEV Community by Navesz (@navesz).</description>
    <link>https://dev.to/navesz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4134679%2F11892279-807d-4094-8d89-787734e0967b.png</url>
      <title>DEV Community: Navesz</title>
      <link>https://dev.to/navesz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/navesz"/>
    <language>en</language>
    <item>
      <title>My code checker was wrong. How I turned its false positives into tests</title>
      <dc:creator>Navesz</dc:creator>
      <pubDate>Wed, 23 Sep 2026 00:37:58 +0000</pubDate>
      <link>https://dev.to/navesz/my-code-checker-was-wrong-how-i-turned-its-false-positives-into-tests-1bim</link>
      <guid>https://dev.to/navesz/my-code-checker-was-wrong-how-i-turned-its-false-positives-into-tests-1bim</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I'm the author of &lt;a href="https://github.com/Navesz/rebar" rel="noopener noreferrer"&gt;rebar&lt;/a&gt;, the open-source checker this post is about. It is alpha.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;rebar fails a CI job when a repository breaks a rule. Examples: formatting nobody checks, a hook git will never run, a credential in a tracked file. A checker like that can fail in one way that matters more than any other: accusing a repository that is doing the right thing. After a couple of those, people stop reading the output. Soon after, they turn it off.&lt;/p&gt;

&lt;p&gt;So I ran it against 28 public repositories and read what it said. Three of the accusations were wrong, and I could prove it. Each case below follows the same order: the accusation, the evidence it was wrong, the fix, and the test that keeps it fixed. The test has to work both ways. It must fail on the old code, and the real violation must still be caught.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. "Git ignores this hook." Not with husky 9.
&lt;/h2&gt;

&lt;p&gt;rebar told &lt;a href="https://github.com/mastra-ai/mastra" rel="noopener noreferrer"&gt;mastra&lt;/a&gt; (commit &lt;code&gt;7e21ff5&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hooks-executable ✗ no execute bit in the index, git ignores them on Linux: .husky/pre-commit
                   — fix with: git update-index --chmod=+x .husky/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file really is mode 100644, and on Linux git skips a hook that isn't executable. The accusation sounds right, and husky 8 users run into exactly that.&lt;/p&gt;

&lt;p&gt;mastra uses husky 9, which works differently. &lt;a href="https://github.com/typicode/husky/blob/v9.1.7/index.js#L14-L22" rel="noopener noreferrer"&gt;husky 9&lt;/a&gt; makes three changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it points &lt;code&gt;core.hooksPath&lt;/code&gt; at &lt;code&gt;.husky/_&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;it writes its own &lt;code&gt;.husky/_/pre-commit&lt;/code&gt; with mode &lt;code&gt;0o755&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;that generated file calls a small script that runs yours with &lt;code&gt;sh -e .husky/pre-commit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git never executes the committed file, so its mode doesn't matter.&lt;/p&gt;

&lt;p&gt;I checked this by running git, not just by reading the husky source. I made a repository with &lt;code&gt;.husky/pre-commit&lt;/code&gt; at 100644, cloned it, ran &lt;code&gt;npm install&lt;/code&gt;, and ran &lt;code&gt;git commit&lt;/code&gt; with &lt;code&gt;GIT_TRACE=1&lt;/code&gt;, which prints the file git runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;husky 9.1.7&lt;/th&gt;
&lt;th&gt;husky 8.0.3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;file git ran&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.husky/_/pre-commit&lt;/code&gt; (generated)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.husky/pre-commit&lt;/code&gt; (committed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rebar before&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rebar after&lt;/td&gt;
&lt;td&gt;not applicable&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I ran it on Windows because Docker wouldn't start on my machine. Windows shows which file git runs. That Linux skips a non-executable hook comes from git's documentation, not from this run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt; exempts the hooks husky 9 manages. It doesn't switch the rule off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tests:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;husky-v9&lt;/code&gt; has two sides with the same bytes and the same 100644 mode. The only difference is the husky version the repository declares. The new code passes one side and fails the other. The old code fails both, which is what makes it a regression test.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;husky-own-hook&lt;/code&gt; declares husky 9, but also has a hook that git runs directly (&lt;code&gt;tooling/hooks/pre-push&lt;/code&gt;) at 100644. Declaring husky must not silence that one, and it doesn't.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. "Rotate this credential." It's AWS's documentation example.
&lt;/h2&gt;

&lt;p&gt;rebar told &lt;a href="https://github.com/motdotla/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; (commit &lt;code&gt;f6390d1&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hardcoded-secret ✗ 10 credential(s) in tracked files … deleting the line is not enough,
                   what is in history has to be ROTATED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six of the ten were not credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AWS_ACCESS_KEY_ID=AKIAIOSF••••••••••••&lt;/code&gt;, twice. That's the example key pair from AWS's own IAM documentation.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;PRIVATE_KEY&lt;/code&gt; in the README whose body is &lt;code&gt;Kh9NV...&lt;/code&gt;, twice. It was cut short on purpose.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PASSWORD: 'password'&lt;/code&gt;, in two tests. The value is just the word.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A secret scanner that tells people to rotate AWS's example key loses its audience fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt; releases those three shapes and nothing near them. &lt;strong&gt;The tests&lt;/strong&gt; are built so the fix can't turn into a hole:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vendor-example&lt;/code&gt;: the failing side is the same file, and it even keeps AWS's example secret key. Only the access key ID changes, to one that isn't a published example, and it must still be flagged. A check for "contains EXAMPLE" would let it through.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;elided-pem&lt;/code&gt;: the failing side has an ellipsis too, but between real 64-character key lines. That's what someone does when they paste a real key into docs and cut out the middle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value-is-the-word&lt;/code&gt;: the same test fixture and the same key, with a value that isn't the word.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This fix nearly shipped wrong. Its first version removed 45 findings from mastra and &lt;strong&gt;added 6&lt;/strong&gt;, and the total still went down. A count only shows the net change. So for this post I ran the scanner again with full lists on every repository, at the same commits, and compared finding by finding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;151 findings removed, 0 added;&lt;/li&gt;
&lt;li&gt;I read each removed line in the original repository;&lt;/li&gt;
&lt;li&gt;107 were the word itself, 28 were AWS's example pair, 9 were shortened keys, and 7 were placeholders like &lt;code&gt;mypassword&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;none was a real credential.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;dotenv's other four findings are &lt;code&gt;.env&lt;/code&gt; files used as test fixtures. rebar still flags them, on purpose, because it flags any committed &lt;code&gt;.env&lt;/code&gt; whatever is in it. I haven't settled that design question, and I didn't touch it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. "Nothing fails when a file is out of format." The next step does.
&lt;/h2&gt;

&lt;p&gt;rebar told &lt;a href="https://github.com/e2b-dev/e2b" rel="noopener noreferrer"&gt;e2b&lt;/a&gt; (commit &lt;code&gt;ccaf9fc&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;formatter ✗ script format only rewrites — nothing fails when a file is out of format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;format&lt;/code&gt; script is &lt;code&gt;prettier --write&lt;/code&gt;, which only rewrites. But &lt;a href="https://github.com/e2b-dev/e2b/blob/ccaf9fc0ffe6ac39c7ec786af7608ab1de19467b/.github/workflows/lint.yml#L88-L98" rel="noopener noreferrer"&gt;e2b's lint workflow&lt;/a&gt; runs &lt;code&gt;pnpm run format&lt;/code&gt; and then fails the job if &lt;code&gt;git status --porcelain&lt;/code&gt; isn't empty. Rewriting and then failing on any difference is a formatting check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt; recognizes that pattern, but only inside a single job. A &lt;code&gt;git diff --exit-code&lt;/code&gt; in another job looks at a different checkout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tests:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;write-then-verify&lt;/code&gt; must pass;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;write-then-verify-other-job&lt;/code&gt; splits the same two commands across two jobs, and it must fail;&lt;/li&gt;
&lt;li&gt;both of the sides that should pass fail on the old code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also ran rebar's GitHub Action on a runner with only this rule. &lt;code&gt;prettier --write .&lt;/code&gt; exits 1 and &lt;code&gt;prettier --check .&lt;/code&gt; exits 0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did the fixes generalize?
&lt;/h2&gt;

&lt;p&gt;Seven of the 28 repositories are where I found these problems, and I wrote the fixes looking at them, so of course they pass there. The other 21 came from a search rule I wrote before measuring anything. Those 21 are the real test.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;7 chosen, before → after&lt;/th&gt;
&lt;th&gt;21 searched, before → after&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;hooks-executable&lt;/code&gt;, repos flagged&lt;/td&gt;
&lt;td&gt;1 → 0&lt;/td&gt;
&lt;td&gt;4 → 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;hardcoded-secret&lt;/code&gt;, findings&lt;/td&gt;
&lt;td&gt;1319 → 1202&lt;/td&gt;
&lt;td&gt;664 → 630&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;formatter&lt;/code&gt;, repos flagged&lt;/td&gt;
&lt;td&gt;4 → 2&lt;/td&gt;
&lt;td&gt;14 → 14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;husky: 4 → 1.&lt;/strong&gt; The one left, agentscope, is still a false positive. Its husky 9 hook lives in &lt;code&gt;examples/web_ui/&lt;/code&gt;, a package inside the repository, and rebar only looks for husky at the root. Still open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets:&lt;/strong&gt; 34 fewer findings in the searched group, all placeholders, none added. I haven't classified the 1832 findings that remain, so I make no claim about them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;formatter: no.&lt;/strong&gt; 14 → 14. I read all 16 repositories still flagged across both groups and followed everything their CI calls:

&lt;ul&gt;
&lt;li&gt;12 are correct: nothing fails on bad formatting.&lt;/li&gt;
&lt;li&gt;4 are still wrong:&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/oraios/serena" rel="noopener noreferrer"&gt;serena&lt;/a&gt; runs &lt;code&gt;poe lint&lt;/code&gt;, which runs &lt;code&gt;ruff format --check&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/topoteretes/cognee" rel="noopener noreferrer"&gt;cognee&lt;/a&gt; runs &lt;code&gt;ruff format --check&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alibaba/page-agent" rel="noopener noreferrer"&gt;page-agent&lt;/a&gt; runs a &lt;code&gt;scripts/ci.js&lt;/code&gt; that calls &lt;code&gt;prettier --check&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;dotenv runs &lt;code&gt;npm test&lt;/code&gt;, which runs &lt;code&gt;standard&lt;/code&gt;. That last one is arguable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ten verdicts changed in total. Every one went from failing to passing or not applicable, and no repository was newly accused.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checker's checker was wrong too
&lt;/h2&gt;

&lt;p&gt;My first script for sorting those formatter results said "13 correct, 1 false positive". It looked for the check only on the workflow line itself, and didn't follow &lt;code&gt;poe lint&lt;/code&gt; or &lt;code&gt;node scripts/ci.js&lt;/code&gt;: the same blind spot as the rule it was auditing. The version before that read files through the API, swallowed an error, and reported "no check" for cognee. Both are fixed, and both now fail loudly. I mention them because they are the same bug as the rule: a checker that is wrong without saying so.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not show
&lt;/h2&gt;

&lt;p&gt;The searched repositories were picked partly by the &lt;code&gt;mcp&lt;/code&gt; topic, and rebar has rules aimed at MCP server setups. This audit says nothing about those rules. I didn't classify their findings, and there's no comparison group of projects without MCP. So I can't say whether MCP projects are riskier, or whether those signatures catch a real attack. Answering that would need a study of its own.&lt;/p&gt;

&lt;p&gt;Three fixed false positives aren't an accuracy rate either. They are three bugs, and each one now has a test that fails on the old code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it on your project and send me a reproducible false positive
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx github:Navesz/rebar#v0.1.0 &lt;span class="nb"&gt;.&lt;/span&gt;
npx &lt;span class="nt"&gt;-p&lt;/span&gt; github:Navesz/rebar#v0.1.0 rebar-security &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in CI, as a &lt;a href="https://github.com/marketplace/actions/rebar-repository-ruler-and-merge-gate" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt;, pinned to the release commit. A tag can be moved; a commit can't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Navesz/rebar@9d39f1e3ed4cd3190b4635dccf22d7b815a74d5b&lt;/span&gt; &lt;span class="c1"&gt;# v0.1.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ruler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;both&lt;/span&gt;   &lt;span class="c1"&gt;# check · security · both&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it flags something that is correct, &lt;a href="https://github.com/Navesz/rebar/issues/new?template=false-positive.yml" rel="noopener noreferrer"&gt;open a false-positive issue&lt;/a&gt; with the rule id, the line it printed, and a public commit or a minimal repository. Every case above started as one wrong line of output, and each one is now a test.&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: method and full tables
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Versions.&lt;/strong&gt; Before: rebar &lt;a href="https://github.com/Navesz/rebar/commit/9f78d9b6e02f2d8c22bc5bfb67fbdd23de2ac2bc" rel="noopener noreferrer"&gt;&lt;code&gt;9f78d9b&lt;/code&gt;&lt;/a&gt;. After: &lt;a href="https://github.com/Navesz/rebar/commit/58aff2ca6b88dc6a0b77b9430313bab5ef009c58" rel="noopener noreferrer"&gt;&lt;code&gt;58aff2c&lt;/code&gt;&lt;/a&gt;. The v0.1.0 release (&lt;code&gt;9d39f1e&lt;/code&gt;) has the same rules: only the Action, its workflow and the changelog differ. The fixes landed in &lt;a href="https://github.com/Navesz/rebar/pull/41" rel="noopener noreferrer"&gt;#41&lt;/a&gt; (husky, formatter, ci-gates, env-example) and &lt;a href="https://github.com/Navesz/rebar/pull/40" rel="noopener noreferrer"&gt;#40&lt;/a&gt; (secrets).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample.&lt;/strong&gt; 28 repositories, fixed before any result was seen and not extended afterwards.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;7 chosen&lt;/strong&gt;, because the fixes came from them: mastra, dotenv, stagehand, biome, e2b, serena, skyvern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;21 from a GitHub search:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;topic &lt;code&gt;mcp&lt;/code&gt;, &lt;code&gt;ai-agents&lt;/code&gt; or &lt;code&gt;developer-tools&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;300–40,000 stars, pushed after 2026-07-24;&lt;/li&gt;
&lt;li&gt;not archived, not a fork;&lt;/li&gt;
&lt;li&gt;TypeScript, JavaScript or Python;&lt;/li&gt;
&lt;li&gt;not a collection (awesome lists, skills, templates);&lt;/li&gt;
&lt;li&gt;at most 300 MB;&lt;/li&gt;
&lt;li&gt;top by stars.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;mastra (1.8 GB) and skyvern (623 MB) break the size cap. I kept them because they're among the chosen seven.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Measurement.&lt;/strong&gt; Each repository was cloned at depth 50 and measured with both rulers and both versions: 112 runs, 0 errors. The commit measured for each repository is in the raw data. The secrets comparison ran the scanner again with full lists at those same commits, because the ruler's summary cuts each list at about 12 items.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other verdicts that changed&lt;/strong&gt; (not among the three cases):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ci-gates&lt;/code&gt; on dotenv, because &lt;code&gt;npm test&lt;/code&gt; chains &lt;code&gt;npm run lint&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ci-gates&lt;/code&gt; on stagehand, because &lt;code&gt;pnpm check&lt;/code&gt; runs &lt;code&gt;turbo run fmt:check lint typecheck&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;env-example&lt;/code&gt; on serena, because the variable it flagged is one the repository &lt;em&gt;writes&lt;/em&gt; into a child process's environment and never reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Full table.&lt;/strong&gt; Repositories flagged before → after, with findings in parentheses. Heuristic rules are reported but don't fail the job unless you pass &lt;code&gt;--heuristics&lt;/code&gt;. Overall, &lt;code&gt;rebar-check&lt;/code&gt; exits 1 on 28 of 28 repositories and &lt;code&gt;rebar-security&lt;/code&gt; on 24 of 28, both before and after. Most of that comes from house-convention rules, such as &lt;code&gt;editorconfig&lt;/code&gt; (20 of 21 searched) and &lt;code&gt;ai-coauthorship&lt;/code&gt; (12 of 21). Those rules encode one project's conventions, and these projects never adopted them. That's not a defect on their side.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ruler&lt;/th&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Kind&lt;/th&gt;
&lt;th&gt;7 chosen: repos (findings)&lt;/th&gt;
&lt;th&gt;21 searched: repos (findings)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ai-coauthorship&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;6 → 6 (48 → 48)&lt;/td&gt;
&lt;td&gt;12 → 12 (740 → 740)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ci-gates&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;2 → 0 (2 → 0)&lt;/td&gt;
&lt;td&gt;4 → 4 (4 → 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dependabot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;4 → 4 (4 → 4)&lt;/td&gt;
&lt;td&gt;5 → 5 (5 → 5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;editorconfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;4 → 4 (4 → 4)&lt;/td&gt;
&lt;td&gt;20 → 20 (20 → 20)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;env-example&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;6 → 5 (6 → 5)&lt;/td&gt;
&lt;td&gt;17 → 17 (17 → 17)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fake-ui&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;formatter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;4 → 2 (4 → 2)&lt;/td&gt;
&lt;td&gt;14 → 14 (14 → 14)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git-identity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;td&gt;9 → 9 (9 → 9)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hooks-executable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;1 → 0 (1 → 0)&lt;/td&gt;
&lt;td&gt;4 → 1 (4 → 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;notice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;3 → 3 (3 → 3)&lt;/td&gt;
&lt;td&gt;7 → 7 (7 → 7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;orphan-schema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;phone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;td&gt;2 → 2 (2 → 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;production-url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;4 → 4 (174 → 174)&lt;/td&gt;
&lt;td&gt;14 → 14 (664 → 664)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;raw-hex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;4 → 4 (59 → 59)&lt;/td&gt;
&lt;td&gt;8 → 8 (200 → 200)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;td&gt;2 → 2 (2 → 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;typecheck&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;3 → 3 (3 → 3)&lt;/td&gt;
&lt;td&gt;9 → 9 (9 → 9)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;agent-bypass-invocation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;td&gt;2 → 2 (5 → 5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;control-bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;3 → 3 (84 → 84)&lt;/td&gt;
&lt;td&gt;5 → 5 (5737 → 5737)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disabled-defense&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;td&gt;1 → 1 (2 → 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;env-committed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;2 → 2 (7 → 7)&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hardcoded-secret&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;6 → 6 (1319 → 1202)&lt;/td&gt;
&lt;td&gt;16 → 15 (664 → 630)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hidden-markdown-directive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hidden-unicode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;4 → 4 (114 → 114)&lt;/td&gt;
&lt;td&gt;10 → 10 (508 → 508)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;indirect-exec-change&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;2 → 2 (5 → 5)&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mcp-ansi-escape&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;1 → 1 (1 → 1)&lt;/td&gt;
&lt;td&gt;2 → 2 (91 → 91)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mcp-server-launch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;2 → 2 (2 → 2)&lt;/td&gt;
&lt;td&gt;5 → 5 (10 → 10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mixed-script-token&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;heuristic&lt;/td&gt;
&lt;td&gt;1 → 1 (2 → 2)&lt;/td&gt;
&lt;td&gt;0 → 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;password-without-kdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;deterministic&lt;/td&gt;
&lt;td&gt;1 → 1 (10 → 10)&lt;/td&gt;
&lt;td&gt;4 → 4 (11 → 11)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only the rows the three cases touch were classified by reading. Every other row is a count, not a verdict on whether rebar is right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Raw data:&lt;/strong&gt; the raw JSON from every run, the commit list, the scripts and the classification files are attached to the &lt;a href="https://github.com/Navesz/rebar/releases/tag/v0.1.0" rel="noopener noreferrer"&gt;v0.1.0 release&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>devops</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>Rules in markdown vs rules in CI: what I measured in my own repositories</title>
      <dc:creator>Navesz</dc:creator>
      <pubDate>Sun, 20 Sep 2026 23:32:07 +0000</pubDate>
      <link>https://dev.to/navesz/rules-in-markdown-vs-rules-in-ci-what-i-measured-in-my-own-repositories-4pp0</link>
      <guid>https://dev.to/navesz/rules-in-markdown-vs-rules-in-ci-what-i-measured-in-my-own-repositories-4pp0</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I'm the author of &lt;a href="https://github.com/Navesz/rebar" rel="noopener noreferrer"&gt;rebar&lt;/a&gt;, the open-source tool this post is about. It is alpha, and I'm its only contributor so far.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I keep a written standard for the sites I build with AI coding agents. The complaint that started this project was mine: a lot of it got ignored. Values were hardcoded, parts of the stack were forgotten, the AI was listed as a co-author, the component library was skipped.&lt;/p&gt;

&lt;p&gt;The obvious fix is to write the rules more clearly. Before doing that, I measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;On 2026-08-25 I went through 161 commits across six of my own repositories:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measurement&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repositories without CI&lt;/td&gt;
&lt;td&gt;3 of 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repositories with broken lint at that moment&lt;/td&gt;
&lt;td&gt;the same 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commits with an AI co-author trailer&lt;/td&gt;
&lt;td&gt;41 of 161 (25.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository with the most governance documents&lt;/td&gt;
&lt;td&gt;35 lint errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Six repositories, all mine, is a small sample. I'm not claiming a general result. The last row is what changed my approach. That repository had an &lt;code&gt;AGENTS.md&lt;/code&gt; with a "Hard rules" section, plus &lt;code&gt;SECURITY.md&lt;/code&gt;, &lt;code&gt;GOVERNANCE.md&lt;/code&gt;, &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, and a &lt;code&gt;check&lt;/code&gt; script that chained format, lint, types, tests and build. Nothing ever ran that &lt;code&gt;check&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every rule was written down. None of them was enforced. The short version, as the README puts it: a rule written in markdown has close to zero compliance, and a rule in CI has 100%. The 100% is not a discovery. A required check that fails blocks the merge by construction. The useful part is the consequence: if a rule can move down a level, from prose into something that blocks, it should.&lt;/p&gt;

&lt;p&gt;That needs one condition, and most of what I built came from learning it the hard way: &lt;strong&gt;the enforcement has to be more reliable than the rule it replaces.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Five times the enforcement was the problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. A score that counted nothing as a pass.&lt;/strong&gt; The first version of the checker treated "this rule does not apply here" as a pass. An empty folder with an empty &lt;code&gt;.git/&lt;/code&gt; scored 8 of 14 and tied with the tool's own repository. Now every rule ends in one of three states: passed, failed, or not applicable, with the reason printed. Not applicable leaves the denominator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rebar-check · prumo
  ✓ editorconfig       has .editorconfig
  ✗ dependabot         automated dependency updates  no dependabot, no renovate
  ✓ ci                 has CI
  ✓ ci-gates           CI reaches the verification the repository declares
  – typecheck          has a typecheck script  no TypeScript here
  11 of 13  ·  1 not applicable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(An excerpt of the sample in the README, measured on 2026-08-30 against another project of mine; only five of its rules are shown.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tests that could not tell passed from not applicable.&lt;/strong&gt; Every rule has pass and fail cases. Each case builds a small repository in a temp directory with its own &lt;code&gt;git init&lt;/code&gt;. At first the cases only read the exit code, but "passed" and "not applicable" both exit 0, so 13 of the 20 rules at the time could not be proved that way. When I applied 70 mutations to the checker, 30 survived with the suite fully green. The cases now declare the expected state and read it from &lt;code&gt;--json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. A heuristic with zero true positives.&lt;/strong&gt; A rule for literal colour values, measured on a real repository, gave 7 hits and zero true positives. Five of the seven were comments documenting the rule itself. So heuristics only warn. A heuristic that blocks teaches people to switch the whole output off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. A green gate over a broken product.&lt;/strong&gt; During a rename, the generator started reading a workflow file from a folder where it had a different name. &lt;code&gt;rebar new&lt;/code&gt; crashed with ENOENT, and &lt;code&gt;npm run verify&lt;/code&gt; stayed green for six commits, because no step actually generated a project. There is now a step that does, and it is itself checked by mutation: putting the original defect back makes two of its five tests fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. My own README.&lt;/strong&gt; It got numbers wrong six times ("20 checks" when there were 19, "8 steps" when there were 12). The fix was not more care. Every number that belongs to the tree is now derived from the source and written between invisible markers, and a gate step fails if the document drifts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The only layer an agent cannot edit
&lt;/h2&gt;

&lt;p&gt;Hooks live in &lt;code&gt;.git/hooks&lt;/code&gt; or a &lt;code&gt;core.hooksPath&lt;/code&gt; setting. Workflows live in &lt;code&gt;.github/workflows&lt;/code&gt;. Both are files, and an agent with write access can delete or bypass them. One attack I reproduced against my own gate: &lt;code&gt;git update-index --skip-worktree&lt;/code&gt; on the config file, then rewrite it on disk. &lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git diff&lt;/code&gt; both came back empty, and the gate printed APPROVED. The gate now reads &lt;code&gt;git ls-files -v&lt;/code&gt;, the one command that shows that flag.&lt;/p&gt;

&lt;p&gt;The layer that holds is on the server. rebar's &lt;code&gt;main&lt;/code&gt; has a GitHub ruleset with a required check and &lt;code&gt;bypass_actors: []&lt;/code&gt;, so not even the owner goes around it. I tested it with a planted pull request that deleted &lt;code&gt;.editorconfig&lt;/code&gt;. Both CI jobs failed and the merge was blocked. A direct push to &lt;code&gt;main&lt;/code&gt; is refused too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents read what reviewers don't see
&lt;/h2&gt;

&lt;p&gt;The second ruler, &lt;code&gt;rebar-security&lt;/code&gt;, looks at versioned files for known prompt-injection signatures. It checks invisible Unicode and terminal control bytes, agent settings that run commands or widen approval, and MCP server launches, each fingerprinted so an allowlisted command cannot quietly gain an environment variable. It also flags agent CLIs started with approval turned off, and AI steps in GitHub workflows that text from an outside account can reach. A finding names a position, never the payload, because the output is read by agents too.&lt;/p&gt;

&lt;p&gt;A pass means "no known signature", never "free of injection". The signature list is public, and the attacker moves second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telling the agent before it writes
&lt;/h2&gt;

&lt;p&gt;Projects generated by &lt;code&gt;rebar new&lt;/code&gt; point their agent at an MCP server that serves rebar's rules, the gate steps, and the measured reason behind each rule. The rules artifact is generated from the rulers' source, and the gate regenerates it in memory and fails if the file on disk differs. Changing a rule and forgetting the MCP is not possible without a red build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It does not check Broken Access Control, and it does not run your application.&lt;/li&gt;
&lt;li&gt;Some rules reflect my own stack: a hardcoded Brazilian phone number check, shadcn's &lt;code&gt;components.json&lt;/code&gt;, an allowlist for co-author trailers. On your repository they may be not applicable, or not useful.&lt;/li&gt;
&lt;li&gt;The generator has one preset, a static Next.js site.&lt;/li&gt;
&lt;li&gt;The MCP server needs a checkout and &lt;code&gt;npm ci --prefix mcp&lt;/code&gt;. &lt;code&gt;npx&lt;/code&gt; alone does not start it.&lt;/li&gt;
&lt;li&gt;It is alpha. As of the project's state file it gates one repository for real: its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it, and tell me where it is wrong
&lt;/h2&gt;

&lt;p&gt;It needs Node 22 or newer, has zero runtime dependencies, and never writes to the repository it audits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx github:Navesz/rebar &lt;span class="nb"&gt;.&lt;/span&gt;                       &lt;span class="c"&gt;# format and gate rules&lt;/span&gt;
npx &lt;span class="nt"&gt;-p&lt;/span&gt; github:Navesz/rebar rebar-security &lt;span class="nb"&gt;.&lt;/span&gt;     &lt;span class="c"&gt;# security and prompt-injection signatures&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most useful contribution right now is a false positive. Run it on a repository of yours. When a verdict is wrong, &lt;a href="https://github.com/Navesz/rebar/issues/new?template=false-positive.yml" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; with the exact output and why it is wrong. One reported false positive is worth more than a new rule.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>devops</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
