• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / jobs / 26886467550

03 Jun 2026 01:01PM UTC coverage: 88.948% (+14.0%) from 74.974%
26886467550

push

github

web-flow
v3.0: single clean architecture (remove V1, lease-based queues, secure-by-default)

Complete v3.0 rewrite into a single, clean architecture. The v1 API and the V2\ scaffolding
are removed (no facade, no dual code); the package passes PHPStan level 6 + strict-rules +
codeigniter with NO baseline.

- Definition: Jobs::define()->...->dispatch() fluent builder -> immutable JobDefinition.
- Handlers decoupled from the god-object (JobHandlerInterface / AbstractJobHandler / TypedJobHandler + JobContext).
- One QueueBackend contract (enqueue/fetch(lease)/ack/nack(delay)/abandon/reapExpired) with 5 backends:
  Sync, Database, Redis, Beanstalk, ServiceBus.
- Runtime: one attempt per fetch; real interrupting Timeout; opt-in idempotency; single-instance lock.
- Worker/Cron: jobs:queue:work, jobs:queue:reap, jobs:cronjob:run, jobs:queue:purge.
- Secure-by-default: HMAC-signed envelopes, per-queue handler allowlist, ShellHandler deny-by-default,
  EventHandler allowlist, UrlHandler anti-SSRF.

Resolves audit findings #1,#2,#3,#4,#5,#6,#7,#8,#10,#12,#13,#17,#18,#19,#20,#22.
Tests: 359 (Beanstalk live); line coverage 88.9%; PHPStan/Psalm/Rector/cs green on PHP 8.2-8.5.

BREAKING CHANGE: v1 API removed. See docs/MIGRATION-v1-to-v3.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

983 of 1103 new or added lines in 43 files covered. (89.12%)

15 existing lines in 3 files now uncovered.

1497 of 1683 relevant lines covered (88.95%)

7.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/src/Queues/Signing/EnvelopeSigner.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Queues.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Jobs\Queues\Signing;
15

16
/**
17
 * Signs and verifies the JSON representation of a queue envelope using HMAC-SHA256.
18
 *
19
 * This is the anti-tamper foundation (fix #1): a worker can detect that a queued
20
 * envelope was modified in transit (or forged) before it deserialises and dispatches
21
 * the payload, preventing handler/argument injection on untrusted backends.
22
 *
23
 * Key resolution (constructor): explicit $key, then config('Jobs')->signingKey, then
24
 * env('JOBS_SIGNING_KEY'), then config('Encryption')->key. If none yields a non-empty
25
 * string the signer is "unconfigured" and operates in an insecure pass-through mode
26
 * (sign() returns '' and verify() returns true) which the worker logs as critical.
27
 */
28
final readonly class EnvelopeSigner
29
{
30
    private string $key;
31

32
    public function __construct(?string $key = null)
33
    {
34
        $this->key = $this->resolveKey($key);
44✔
35
    }
36

37
    /**
38
     * True when a non-empty signing key was resolved.
39
     */
40
    public function isConfigured(): bool
41
    {
42
        return $this->key !== '';
42✔
43
    }
44

45
    /**
46
     * Returns the hex HMAC-SHA256 of the given payload, or '' when no key is configured.
47
     */
48
    public function sign(string $payloadJson): string
49
    {
50
        if (! $this->isConfigured()) {
33✔
51
            return '';
22✔
52
        }
53

54
        return hash_hmac('sha256', $payloadJson, $this->key);
11✔
55
    }
56

57
    /**
58
     * Verifies a signature against the payload using a constant-time comparison.
59
     *
60
     * When unconfigured this returns true (insecure pass-through). When configured a
61
     * null or empty signature is rejected.
62
     */
63
    public function verify(string $payloadJson, ?string $signature): bool
64
    {
65
        if (! $this->isConfigured()) {
14✔
66
            return true;
2✔
67
        }
68

69
        if ($signature === null || $signature === '') {
12✔
70
            return false;
2✔
71
        }
72

73
        return hash_equals($this->sign($payloadJson), $signature);
10✔
74
    }
75

76
    /**
77
     * Resolves the signing key with strict null-coalescing semantics: an explicitly
78
     * provided string (even '') short-circuits the chain. Only a null explicit value
79
     * falls back to the Jobs config, then the JOBS_SIGNING_KEY environment variable and
80
     * finally the Encryption key. A resolved key of '' marks the signer as unconfigured.
81
     */
82
    private function resolveKey(?string $explicit): string
83
    {
84
        if ($explicit !== null) {
44✔
85
            return $explicit;
23✔
86
        }
87

88
        $configured = config('Jobs')->signingKey;
21✔
89
        if ($configured !== null) {
21✔
90
            return $configured;
1✔
91
        }
92

93
        $fromEnv = env('JOBS_SIGNING_KEY');
20✔
94
        if (is_string($fromEnv)) {
20✔
NEW
95
            return $fromEnv;
×
96
        }
97

98
        return config('Encryption')->key;
20✔
99
    }
100
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc