Skip to content
Ahmed Anbar edited this page Apr 25, 2026 · 1 revision

FAQ

Quick answers to questions we hear often. For deeper dives, the page links go to the relevant reference.


General

Is DevGuard a replacement for PHPStan / Psalm / Larastan?

No — they solve different problems.

Tool What it catches
PHPStan / Psalm / Larastan Type errors, unreachable code, undefined methods, model attribute typos
DevGuard Production-readiness, deploy-config issues, env consistency, dependency CVEs, code shape (fat controllers, etc.)

Use both. PHPStan finds bugs in your code; DevGuard finds bugs in your deployment. They don't overlap meaningfully.

Is this Laravel-only?

Yes. DevGuard's rules are Laravel-specific (it knows about .env, app/Http/Controllers, composer.lock, etc.). For non-Laravel PHP projects, the env audit and dependency audit could partially apply, but the deploy and architecture rules wouldn't make sense.

If there's appetite, a future "DevGuard Core" could be framework-agnostic — open a GitHub issue if you'd use that.

Why is it called DevGuard?

A guard for developers — it's the gate that catches your obvious mistakes before they cost you. Originally devsanity was the working name, then dev-guard, then settled on the camelCase form.

Who maintains it?

Ahmed Anbar (begnulinux@gmail.com). Solo project so far. Contributions welcome — see Extending DevGuard.

Is it production-ready?

DevGuard itself is in 0.x — minor versions can introduce changes. The CLI is in active use on real Laravel projects (the maintainer's own projects, plus the smoke test). Tests are green, real-world tested, and the JSON / SARIF schemas are stable within a minor.

We're not at 1.0 because there are still patterns we want to settle (plugin discovery, more auto-fix coverage, more CI integrations). But it's safe to use today — just expect minor-version churn until 1.0.


Installation

Should I install per-project or globally?

Per-project (composer require --dev) is the recommended default. Reasons:

  • Every contributor and CI runs the same DevGuard version (committed in composer.lock)
  • Updates are tracked alongside other dependencies
  • No cross-machine "works on my laptop" surprises

Global is fine if you audit many Laravel projects from the same machine and don't want to add a dev dep to each. They're not mutually exclusive.

Can I use DevGuard without composer?

No. The CLI is a Composer-installed PHP package. You can however use the GitHub Action (which bundles composer + the CLI internally) without adding anything to your project's composer.json.

What PHP versions are supported?

Currently PHP 8.2 and 8.3. Tested in CI on both. PHP 8.4 should work — let us know if it doesn't.

Does it require Laravel installed?

No — DevGuard is just a PHP CLI. It detects Laravel by reading your project's composer.json and checking for the laravel/framework require. If your project isn't Laravel, most rules become no-ops or warn.


Running

Why does devguard run all show the Ping tool first every time?

Ping is a sanity-check tool that confirms DevGuard found your project and detected Laravel. It's always green, fast (<10ms), and useful as a "did the install work?" signal. You can skip it by running specific tools:

devguard run deploy,architecture,env,deps

Is there a way to run multiple specific tools?

Currently you run all or one named tool. Multi-tool selection (e.g., devguard run deploy,architecture) isn't supported via the CLI yet — but it works for --tools in install-hook. This is a candidate for a future minor release.

Workaround: run them sequentially in shell:

devguard run deploy && devguard run architecture && devguard run env

Can I run only specific rules within a tool?

Not via CLI flag. Use Configuration to disable individual rules at the config level, or use @devguard-ignore annotations for one-off skips.

How fast is it on a real codebase?

Typical benchmarks on a medium Laravel app (200 files, 50 controllers):

Run Time
devguard run ping <50ms
devguard run deploy ~100ms
devguard run architecture ~500ms (AST scanning)
devguard run env ~500ms (AST scanning)
devguard run deps ~2s (network call to packagist)
devguard run all ~2.5s
devguard run all --changed-only (3 files) <300ms

These scale roughly linearly with codebase size. Big monorepos (1000+ files) can take ~10s for all; use --changed-only for hooks on big repos.


Output and integration

Can I get the audit as a markdown file?

Not natively — DevGuard ships console / JSON / HTML / SARIF. You can convert JSON to markdown with jq:

devguard run all --json | jq -r '
    "# DevGuard Report\n",
    .tools[] | "## " + (.name | ascii_upcase),
    "\n",
    (.results[] | "- " + .status + ": " + .message)
'

How do I post DevGuard results to Slack on every PR?

GitHub Actions example:

- name: Notify Slack
  if: failure()   # only on red
  uses: rtCamp/action-slack-notify@v2
  env:
    SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
    SLACK_MESSAGE: 'DevGuard found issues on ${{ github.event.pull_request.title }}'

For richer messages with the actual findings, parse JSON output and POST to a Slack webhook directly. See Other CI Systems.

Can DevGuard write to a database?

Not directly. Use --json and pipe to a script that inserts findings into your DB:

devguard run all --json | python3 ingest_audit_findings.py

This is a common pattern for orgs running DevGuard across many projects and wanting a unified dashboard.


Auto-fix

Why isn't auto-fix available for all rules?

Because not all fixes are mechanical. APP_DEBUG=true → false looks trivial but flipping it on a developer's local machine breaks debugging. Architecture refactors require understanding the domain. The general rule: if the suggestion has any "depending on your environment" qualifier, it's not auto-fixable.

See Auto-fix → When not to use auto-fix.

Why does devguard fix env need to run twice for some fixes?

Cross-file fixes have a deliberate two-step flow:

  1. First run: append the new key to .env.example (the public template)
  2. Second run: append the same key to .env (the local file with real values)

Combining both into one auto-fix would teach users to commit secrets-shaped values into .env.example. The two-step forces a review pause between template and instance. See Auto-fix → Two-step flow.

Will fix deps introduce breaking changes?

It runs composer update <package> --with-dependencies, which honors your version constraints. It won't pull in a major version bump unless your composer.json already allows it. So:

  • ^1.5.0 constraint → fix updates to latest 1.x — usually safe
  • ^1.5.0 || ^2.0.0 constraint → fix may update to latest 2.x — possibly breaking, review the diff

Always review composer.lock changes after fix deps, even if it's just to confirm the version range is what you expect.


Configuration

Can I disable specific findings without changing config?

Yes — three ways:

  1. Baseline file: devguard baseline snapshots all current findings; future runs suppress them
  2. Inline annotation: // @devguard-ignore on the offending line or above it
  3. Configure impact to 0: keeps the check running but stops the score deduction

For new code that triggers a check intentionally, use @devguard-ignore. For bulk legacy adoption, use baseline. For "always false positive on this rule across the project," lower the impact to 0 in config.

See Baseline and Suppression.

How do I make DevGuard stricter?

Add 'fail_on' => 'warning' in config/devguard.php for a tool — turns every warning into a failure. Or set fail-on-warning: 'true' on the GitHub Action.

For per-rule strictness, raise impact values (e.g., 'debug_mode' => ['impact' => 30]) — making a single failure drop the score below the gate threshold.

Can I make a rule lazier?

Set its impact to 0 — keeps it visible in reports without affecting the score. For tools (the whole group), 'enabled' => false removes it entirely.


CI

Does the GitHub Action work on private repos?

Yes. The Action's Docker image is public (anyone can pull it), but the runner can be on a private repo. permissions: security-events: write works on private repos exactly the same way (assuming GitHub Advanced Security is enabled, which is automatic for public repos and a paid feature for private orgs).

Does it work on self-hosted runners?

Yes, assuming the runner has Docker (the Action is Docker-based). Self-hosted ARM runners need to confirm composer:2 image runs there (it should, but verify).

Why pin to @v1 and not @v1.1.2?

@v1 is the rolling tag — auto-updates with patch releases. Most teams want the latest CLI fixes flowing in automatically (especially security fixes). For regulated environments needing byte-for-byte reproducibility, pin to @v1.1.2.

If you want notifications on Action updates, watch the devguard-action repo — every patch release shows up there.

Will SARIF show on the PR's "Files Changed" tab?

Yes, with caveats:

  • The finding must have a real file and line (project-wide findings show up in the PR's checks list, not on the diff)
  • The line must be in the PR's diff (lines unchanged by the PR don't get annotations)
  • Code Scanning must be enabled (free for public repos, paid for private — which is GitHub Advanced Security)

If you're not seeing annotations: check the run's "Code Scanning" check status. If it's green but no annotations, check whether the SARIF actually had findings (look at the artifact).


Privacy / data handling

Does DevGuard send any data anywhere?

The CLI itself: no. It runs entirely locally — reads files, parses ASTs, writes reports. No network calls.

Exceptions:

  • composer audit (used by the deps tool) calls packagist.org to fetch advisory data. This is composer's behavior, not ours. Run composer audit directly to see exactly what it does.
  • The GitHub Action's SARIF upload step posts findings to GitHub's Code Scanning API. That's part of github/codeql-action/upload-sarif, not DevGuard.

No telemetry, no usage tracking, no phone-home. Open the source if you want to verify.

Where do my reports go?

Wherever you tell them to:

  • Console: stdout
  • --json: stdout (or pipe to file)
  • --html: file in your project (default devguard-report.html)
  • --sarif: file in your project (default devguard.sarif)

DevGuard never writes outside the project directory unless --output= or --html= / --sarif= specifies an absolute path elsewhere.


Versioning and stability

What does 1.0 mean for DevGuard?

When DevGuard hits 1.0:

  • Caret semantics will work normally (^1.0>=1.0.0 <2.0.0) — no more OR-chains
  • The JSON / SARIF schemas commit to backward compatibility (no field removals across minors)
  • Plugin discovery (likely): a Composer-plugin pattern for registering third-party tools without editing bin/devguard
  • Stable release cadence

We're not there yet. Until then, expect occasional minor-version migrations.

How often does it release?

No fixed cadence. Recent releases:

Version Date Reason
v0.8.3 2026-04-24 Bug fix: --locked for composer audit
v0.8.2 2026-04-24 Bug fix: declare symfony/process
v0.8.1 2026-04-24 Bug fix: SARIF locations
v0.8.0 2026-04-22 Feature: --changed-only mode
v0.7.2 2026-04-21 Feature: env auto-fix expansion

When something needs fixing, a release happens. When new features land, a release happens. See Changelog and Versioning for the full list.


Where to next

Clone this wiki locally