Search by

rennf93 / symfony-guard

rennf93

Symfony middleware adapter for guard-core-php: maps Symfony HttpFoundation requests to the guard-core engine and block verdicts back to Symfony responses

Package info

github.com/Guard-Core/symfony-guard

pkg:composer/rennf93/symfony-guard

Fund package maintenance!

rennf93

paypal.me/renzof93

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.5.0 2026-10-09 09:21 UTC

README

Guard Core

Symfony middleware adapter for [guard-core-php](https://github.com/Guard-Core/guard-core-php): maps Symfony `HttpFoundation` Request objects to the guard-core engine and translates block verdicts back to Symfony-native responses. Works with Symfony 6.4 LTS and 7.x.

Packagist version Docs Release License CI

PagesBuildDeployment DocsUpdate last-commit

Symfony PHP Downloads

Website · Docs · Playground · Dashboard · Discord

Ecosystem

Guard Core is the Python engine. Framework adapters are thin wrappers that translate native request/response types into Guard Core's protocols. The telemetry agents ship security events and metrics to the monitoring backend. Parallel engine implementations exist for Go, PHP, TypeScript (on npm), and Rust (on crates.io) - all ports of the same reference semantics, conformance-tested against the shared adversarial corpus.

Python

Package Role PyPI
guard-core Framework-agnostic security engine PyPI
guard-agent Telemetry agent PyPI
fastapi-guard FastAPI / Starlette adapter PyPI
flaskapi-guard Flask adapter PyPI
djapi-guard Django adapter PyPI
tornadoapi-guard Tornado adapter PyPI

Go

Go modules published via GitHub releases. Production-ready.

Package Role Release
guard-core-go Go engine release
nethttp-guard net/http adapter release
gin-guard Gin adapter release
echo-guard Echo (v4) adapter release
fiber-guard Fiber (v3) adapter release
guard-agent-go Telemetry agent release

PHP

Published on Packagist under the rennf93 vendor. Production-ready.

Package Role Packagist
guard-core-php PHP engine Packagist
laravel-guard Laravel adapter Packagist
symfony-guard Symfony adapter Packagist
psr15-guard PSR-15 adapter Packagist
slim-guard Slim 4 adapter Packagist
guard-agent-php Telemetry agent Packagist

TypeScript / JavaScript

Published under the @guardcore npm scope; source in the guard-core-ts monorepo. Production-ready.

Package Role npm
@guardcore/core Core engine
@guardcore/express Express adapter npm
@guardcore/nestjs NestJS adapter npm
@guardcore/fastify Fastify adapter npm
@guardcore/hono Hono (edge) adapter npm
guardagent Telemetry agent npm

Rust

Published on crates.io. Production-ready.

Package Role crates.io
guard-core-engine Core engine crate crates.io
guard-core-rs Facade crate (consumer entry point) crates.io
actix-guard-rs Actix Web adapter crates.io
axum-guard-rs Axum adapter crates.io
tower-guard-rs Tower adapter crates.io
rocket-guard-rs Rocket adapter crates.io
guard-agent-rs Telemetry agent crates.io

AI Coding Agents

Package Role PyPI
guard-core-mcp MCP server: config validation, docs search, detection sandbox PyPI

Features

  • The full guard-core-php engine pipeline over Symfony HttpFoundation requests: rate limiting, IP lists, payload inspection, security headers
  • Lifecycle integration with Symfony's middleware stack
  • Configurable behavior notes for passive preview

Documentation

📚 Documentation - full technical documentation for this package.

🛡️ Guard Core - the engine's reference documentation.

🤖 Monitoring Agent Integration - monitor your Guard instance with a monitoring agent.

Install

composer require rennf93/symfony-guard

Usage

Wrap your kernel with the middleware (front controller or wherever the kernel is assembled):

use RenzoFranceschini\GuardCore\Config\SecurityConfig;
use RenzoFranceschini\GuardCore\Engine\GuardEngine;
use RenzoFranceschini\GuardCoreSymfony\GuardMiddleware;
use Symfony\Component\HttpFoundation\Request;

// Anywhere your App\Kernel is created
$kernel = new GuardMiddleware(
    new App\Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']),
    new GuardEngine(new SecurityConfig(
        enableRedis: false,
        blacklist: ['192.0.2.0/24'],
        rateLimit: 100,
        rateLimitWindow: 60,
        enableRateLimiting: true,
    ))
);
// public/index.php
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Blocked requests get the engine's block verdict translated exactly (status, body, headers) as a Symfony\Component\HttpFoundation\Response: 403 Forbidden for a blacklisted IP, 429 Too many requests with Retry-After for a rate limit hit. Passing requests continue into the wrapped kernel untouched.

Pass-through responses are finished by the middleware too: the engine's security headers and CORS verdict headers are merged on top of the kernel's response, and the engine's behavioral return rules observe the response status code plus a body prefix bounded by behaviorMaxResponseBodyInspectBytes (only while behaviorScanResponseBody is on). Per-route configuration attaches through the middleware's route map or a custom resolver:

use RenzoFranceschini\GuardCore\Routing\RouteConfig;
use RenzoFranceschini\GuardCoreSymfony\GuardMiddleware;

return new GuardMiddleware(
    $kernel,
    new GuardEngine($config),
    routes: [
        '/docs/' => new RouteConfig(enableSuspiciousDetection: false),
        '/api/' => new RouteConfig(rateLimit: 5, rateLimitWindow: 10),
    ],
    // optional: country resolver for RouteConfig geoRateLimits tiers
    geoRateLimitResolver: $myResolver,
    // optional: custom resolver receiving the Symfony request
    routeResolver: fn (Request $r) => str_starts_with($r->getPathInfo(), '/admin') ? new RouteConfig(bypassedChecks: ['rate_limit']) : null,
);

routes patterns match a path exactly or as a prefix when they end with /. Geo rate-limit tiers need a country resolver: pass geoRateLimitResolver explicitly, or configure geoIpHandler together with blockedCountries/whitelistCountries (the engine keeps the injected handler only when country lists are set) and the middleware bridges it onto the engine's rate-limit handler automatically.

Lifecycle

PHP shared-nothing applies: construct GuardEngine (and therefore GuardMiddleware) per request in classic FPM, or per worker under long-running runtimes (FrankenPHP, RoadRunner, workerman). The middleware holds no mutable state of its own. In-memory fallbacks are per-request safety nets; distributed rate limits, IP bans, and cloud-range caches require Redis (set enableRedis: true and point REDIS_HOST/REDIS_PORT at your instance).

Behavior notes

  • Fail-closed: if the engine throws, the middleware returns the engine's fail-closed response (500 Security check failed, honorably overridden by customErrorResponses) instead of letting the request through.
  • Main request only: the middleware screens the main kernel request and passes sub-requests straight into the wrapped kernel. Sub-requests are internal and derived from a main request that was already screened; screening them again would double-count rate-limit hits (fragments, forwards).
  • Bounded body read: the request body is scanned as a prefix of at most 256 KiB (SymfonyGuardRequest::MAX_BODY_BYTES, matching the engine's full-scan window). The framework materializes the full body in memory; the engine only ever sees the capped prefix. Payloads beyond the prefix, or signatures split across its boundary, are not detected.
  • Client address: the adapter maps the engine's clientHost() onto $request->getClientIp(). Without Symfony's trusted-proxies configuration that is the connecting REMOTE_ADDR, and the engine's own trusted_proxies / X-Forwarded-For resolution applies. With Symfony trusted proxies configured, Symfony resolves the forwarded chain first and the engine sees the resolved client. Pick one side to do the resolving; configuring both can double-hop.
  • With redisFailOpen: true the middleware constructs and serves requests even when Redis is unreachable; with redisFailOpen: false construction fails closed.
  • No security headers or CORS are added by this adapter. (Symfony response mechanics put a Date and a private Cache-Control on every response object; the engine's own headers are copied exactly.)

Testing

composer lint
composer test

composer test runs the plain-PHP suite in bin/test_symfony.php (unit coverage always; set REDIS_HOST to a reachable Redis to include the shared-state integration cases).

Status

Released: v1.1.0 on Packagist. The engine floor is rennf93/guard-core-php ^4.1.0; no 4.1.0 of the engine is currently published (its tag is absent and Packagist's latest is v4.0.4), so public resolution is collapsed until the synchronized 4.2.0 train retags the engine - CI resolves the engine from the master sibling checkout in the meantime.

License

MIT