403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /proc/2798582/cwd/scripts/ci/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /proc/2798582/cwd/scripts/ci/composer-audit-gate.php
<?php

declare(strict_types=1);

/**
 * Plan 270 §Phase 7 — Composer audit CI gate.
 *
 * Reads `composer audit --format=json` output on stdin, filters out
 * advisories acknowledged in `scripts/ci/composer-audit-baseline.json`,
 * and fails the build only on NEW high or critical advisories.
 *
 * Why a baseline file: the repo inherits a backlog of high/critical
 * advisories on transitive dependencies. Blocking every merge until
 * the entire backlog clears is hostile; blocking on NEW ones the day
 * they land is the right tradeoff. Each baseline entry must have an
 * owner + a target date to keep the list from rotting.
 *
 * Low + medium advisories surface as a CI annotation (non-blocking)
 * so the team sees them without the merge queue jamming.
 *
 * Exit codes:
 *   0 -> no new high/critical advisories outside the baseline
 *   1 -> at least one new high/critical advisory found
 *   2 -> usage / parsing error
 *
 * Usage (in CI):
 *   composer audit --format=json --no-dev | php scripts/ci/composer-audit-gate.php
 */

$baselinePath = __DIR__.'/composer-audit-baseline.json';
$baseline = [];
if (is_file($baselinePath)) {
    $rawBaseline = file_get_contents($baselinePath);
    if ($rawBaseline === false) {
        fwrite(STDERR, "composer-audit-gate: could not read baseline file at {$baselinePath}\n");
        exit(2);
    }
    $decoded = json_decode($rawBaseline, true);
    if (! is_array($decoded) || ! isset($decoded['acknowledged']) || ! is_array($decoded['acknowledged'])) {
        fwrite(STDERR, "composer-audit-gate: baseline is malformed (expecting {\"acknowledged\": [...]})\n");
        exit(2);
    }
    foreach ($decoded['acknowledged'] as $entry) {
        if (is_array($entry) && isset($entry['advisoryId']) && is_string($entry['advisoryId'])) {
            $baseline[$entry['advisoryId']] = $entry;
        }
    }
}

$stdin = stream_get_contents(STDIN);
if ($stdin === false || trim($stdin) === '') {
    fwrite(STDERR, "composer-audit-gate: no audit JSON on stdin\n");
    exit(2);
}

$payload = json_decode($stdin, true);
if (! is_array($payload)) {
    fwrite(STDERR, "composer-audit-gate: stdin was not valid JSON\n");
    exit(2);
}

$advisories = $payload['advisories'] ?? [];
if (! is_array($advisories)) {
    $advisories = [];
}

$newBlocking = [];
$baselineHits = [];
$lowMedium = [];

foreach ($advisories as $packageAdvisories) {
    if (! is_array($packageAdvisories)) {
        continue;
    }
    foreach ($packageAdvisories as $advisory) {
        if (! is_array($advisory)) {
            continue;
        }
        $severity = strtolower((string) ($advisory['severity'] ?? ''));
        $id = (string) ($advisory['advisoryId'] ?? '');
        if ($id === '') {
            // Advisories without an id can't be baselined deterministically;
            // treat as blocking when high/critical, surface otherwise.
            if (in_array($severity, ['high', 'critical'], true)) {
                $newBlocking[] = $advisory;
            } else {
                $lowMedium[] = $advisory;
            }

            continue;
        }

        if (in_array($severity, ['high', 'critical'], true)) {
            if (isset($baseline[$id])) {
                $baselineHits[] = ['advisory' => $advisory, 'baseline' => $baseline[$id]];
            } else {
                $newBlocking[] = $advisory;
            }
        } elseif (in_array($severity, ['low', 'medium'], true)) {
            $lowMedium[] = $advisory;
        }
    }
}

// Emit a baseline-rot warning: any baseline entry whose target_date is in
// the past should be cleared, not extended silently.
$now = new \DateTimeImmutable;
$rotted = [];
foreach ($baseline as $entry) {
    if (! isset($entry['target_date']) || ! is_string($entry['target_date'])) {
        continue;
    }
    try {
        $target = new \DateTimeImmutable($entry['target_date']);
    } catch (\Throwable) {
        continue;
    }
    if ($target < $now) {
        $rotted[] = $entry;
    }
}

if ($lowMedium !== []) {
    fwrite(STDOUT, "::warning::composer audit found ".count($lowMedium)." low/medium advisory(ies) — non-blocking. Run `composer audit` locally for details.\n");
}

if ($rotted !== []) {
    fwrite(STDOUT, "::warning::composer-audit baseline has ".count($rotted)." entry(ies) past their target_date. Review or clear them.\n");
    foreach ($rotted as $entry) {
        fwrite(STDOUT, "  - {$entry['advisoryId']} ({$entry['packageName']}) target {$entry['target_date']} owner {$entry['owner']}\n");
    }
}

if ($baselineHits !== []) {
    fwrite(STDOUT, "composer-audit-gate: ".count($baselineHits)." high/critical advisory(ies) matched the baseline and were allowed:\n");
    foreach ($baselineHits as $hit) {
        $a = $hit['advisory'];
        $b = $hit['baseline'];
        fwrite(STDOUT, "  - {$a['advisoryId']} {$a['packageName']} ({$a['severity']}) owner={$b['owner']} target={$b['target_date']}\n");
    }
}

if ($newBlocking === []) {
    fwrite(STDOUT, "composer-audit-gate: OK (no new high/critical advisories)\n");
    exit(0);
}

fwrite(STDERR, "\ncomposer-audit-gate: FAILED — ".count($newBlocking)." new high/critical advisory(ies) outside the baseline:\n\n");
foreach ($newBlocking as $advisory) {
    $id = $advisory['advisoryId'] ?? '<no id>';
    $pkg = $advisory['packageName'] ?? '<unknown>';
    $sev = $advisory['severity'] ?? '<unknown>';
    $title = $advisory['title'] ?? '';
    $cve = $advisory['cve'] ?? null;
    fwrite(STDERR, "  - [{$sev}] {$id} {$pkg} {$cve}\n    {$title}\n");
    fwrite(STDOUT, "::error title=composer audit::[{$sev}] {$pkg}: {$title} ({$id})\n");
}

fwrite(STDERR, "\nResolution options:\n");
fwrite(STDERR, "  1. Upgrade the affected package (`composer update <pkg>`).\n");
fwrite(STDERR, "  2. If upgrade isn't feasible, add an entry to scripts/ci/composer-audit-baseline.json\n");
fwrite(STDERR, "     with `owner`, `target_date`, and `notes` explaining the deferral.\n\n");
exit(1);

Youez - 2016 - github.com/yon3zu
LinuXploit